1/** 2 * @file create_bfd.c 3 * Routine to handle elf file creation 4 * 5 * @remark Copyright 2007 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Jens Wilke 9 * @Modifications Maynard Johnson 10 * @Modifications Philippe Elie 11 * @Modifications Daniel Hansel 12 * 13 * Copyright IBM Corporation 2007 14 * 15 */ 16 17#include "opjitconv.h" 18#include "opd_printf.h" 19#include "op_libiberty.h" 20 21#include <bfd.h> 22#include <stdint.h> 23#include <stdio.h> 24 25/* Create the symbols and fill the syms array for all functions 26 * from start_idx to end_idx pointing into entries_address_ascending array */ 27static int fill_symtab(void) 28{ 29 int rc = OP_JIT_CONV_OK; 30 u32 i; 31 int r; 32 struct jitentry const * e; 33 asymbol * s; 34 asection * section = NULL; 35 36 /* Check for valid value of entry_count to avoid integer overflow. */ 37 if (entry_count > UINT32_MAX - 1) { 38 bfd_perror("invalid entry_count value"); 39 rc = OP_JIT_CONV_FAIL; 40 goto out; 41 } 42 43 syms = xmalloc(sizeof(asymbol *) * (entry_count+1)); 44 syms[entry_count] = NULL; 45 for (i = 0; i < entry_count; i++) { 46 e = entries_address_ascending[i]; 47 if (e->section) 48 section = e->section; 49 s = bfd_make_empty_symbol(cur_bfd); 50 if (!s) { 51 bfd_perror("bfd_make_empty_symbol"); 52 rc = OP_JIT_CONV_FAIL; 53 goto out; 54 } 55 s->name = e->symbol_name; 56 s->section = section; 57 s->flags = BSF_GLOBAL | BSF_FUNCTION; 58 s->value = e->vma - section->vma; 59 verbprintf(debug,"add sym: name=%s, value=%llx\n", s->name, 60 (unsigned long long)s->value); 61 syms[i] = s; 62 } 63 r = bfd_set_symtab(cur_bfd, syms, entry_count); 64 if (r == FALSE) { 65 bfd_perror("bfd_set_symtab"); 66 rc = OP_JIT_CONV_FAIL; 67 } 68out: 69 return rc; 70} 71 72/* 73 * create a new section. 74 */ 75asection * create_section(bfd * abfd, char const * section_name, 76 size_t size, bfd_vma vma, flagword flags) 77{ 78 asection * section; 79 80 verbprintf(debug, "create_section() %s\n", section_name); 81 section = bfd_make_section(abfd, section_name); 82 if (section == NULL) { 83 bfd_perror("bfd_make_section"); 84 goto error; 85 } 86 if (bfd_set_section_vma(abfd, section, vma) == FALSE) { 87 bfd_perror("bfd_set_section_vma"); 88 goto error; 89 } 90 if (bfd_set_section_size(abfd, section, size) == FALSE) { 91 bfd_perror("bfd_set_section_size"); 92 goto error; 93 } 94 if (bfd_set_section_flags(abfd, section, flags) == FALSE) { 95 bfd_perror("bfd_set_section_flags"); 96 goto error; 97 } 98 return section; 99error: 100 return NULL; 101} 102 103 104/* create a .text section. end_idx: index last jitentry (inclusive!) */ 105static int create_text_section(int start_idx, int end_idx) 106{ 107 int rc = OP_JIT_CONV_OK; 108 109 asection * section; 110 char const * section_name; 111 int idx = start_idx; 112 unsigned long long vma_start = 113 entries_address_ascending[start_idx]->vma; 114 struct jitentry * ee = entries_address_ascending[end_idx]; 115 unsigned long long vma_end = ee->vma + ee->code_size; 116 int size = vma_end - vma_start; 117 118 section_name = bfd_get_unique_section_name(cur_bfd, ".text", &idx); 119 verbprintf(debug, "section idx=%i, name=%s, vma_start=%llx, size=%i\n", 120 idx, section_name, vma_start, size); 121 122 section = create_section(cur_bfd, section_name, size, vma_start, 123 SEC_ALLOC|SEC_LOAD|SEC_READONLY|SEC_CODE|SEC_HAS_CONTENTS); 124 if (section) 125 entries_address_ascending[start_idx]->section = section; 126 else 127 rc = OP_JIT_CONV_FAIL; 128 129 return rc; 130} 131 132/* fill a section contents at a given offset from the start of the section */ 133int fill_section_content(bfd * abfd, asection * section, 134 void const * b, file_ptr offset, size_t sz) 135{ 136 if (bfd_set_section_contents(abfd, section, b, offset, sz) == FALSE) { 137 bfd_perror("bfd_set_section_contents"); 138 return OP_JIT_CONV_FAIL; 139 } 140 return OP_JIT_CONV_OK; 141} 142 143/* 144 * Copy all code of the functions that are within start_idx and end_idx to 145 * the section. 146 */ 147static int fill_text_section_content(asection * section, int start_idx, 148 int end_idx) 149{ 150 int rc = OP_JIT_CONV_OK; 151 unsigned long long vma_start = 152 entries_address_ascending[start_idx]->vma; 153 struct jitentry const * e; 154 int i; 155 156 for (i = start_idx; i <= end_idx; i++) { 157 e = entries_address_ascending[i]; 158 verbprintf(debug, "section = %s, i = %i, code = %llx," 159 " vma = %llx, offset = %llx," 160 "size = %i, name = %s\n", 161 section->name, i, 162 (unsigned long long) (uintptr_t) e->code, 163 e->vma, e->vma - vma_start, 164 e->code_size, e->symbol_name); 165 /* the right part that is created by split_entry may 166 * have no code; also, the agent may have passed NULL 167 * for the code location. 168 */ 169 if (e->code) { 170 rc = fill_section_content(cur_bfd, section, 171 e->code, (file_ptr) (e->vma - vma_start), 172 (bfd_size_type)e->code_size); 173 if (rc != OP_JIT_CONV_OK) 174 break; 175 } 176 } 177 return rc; 178} 179 180 181/* Walk over the symbols sorted by address and create ELF sections. Whenever we 182 * have a gap greater or equal to 4096 make a new section. 183 */ 184int partition_sections(void) 185{ 186 int rc = OP_JIT_CONV_OK; 187 u32 i, j; 188 struct jitentry const * pred; 189 struct jitentry const * entry; 190 unsigned long long end_addr; 191 192 // i: start index of the section 193 i = 0; 194 for (j = 1; j < entry_count; j++) { 195 entry = entries_address_ascending[j]; 196 pred = entries_address_ascending[j - 1]; 197 end_addr = pred->vma + pred->code_size; 198 // calculate gap between code, if it is more than one page 199 // create an additional section 200 if ((entry->vma - end_addr) >= 4096) { 201 rc = create_text_section(i, j - 1); 202 if (rc == OP_JIT_CONV_FAIL) 203 goto out; 204 i = j; 205 } 206 } 207 // this holds always if we have at least one jitentry 208 if (i < entry_count) 209 rc = create_text_section(i, entry_count - 1); 210out: 211 return rc; 212} 213 214 215/* Fill the code content into the sections created by partition_sections() */ 216int fill_sections(void) 217{ 218 int rc = OP_JIT_CONV_OK; 219 u32 i, j; 220 asection * section; 221 222 rc = fill_symtab(); 223 if (rc == OP_JIT_CONV_FAIL) 224 goto out; 225 226 verbprintf(debug, "opjitconv: fill_sections\n"); 227 i = 0; 228 for (j = 1; j < entry_count; j++) { 229 if (entries_address_ascending[j]->section) { 230 section = entries_address_ascending[i]->section; 231 rc = fill_text_section_content(section, i, 232 j - 1); 233 if (rc == OP_JIT_CONV_FAIL) 234 goto out; 235 i = j; 236 } 237 } 238 // this holds always if we have at least one jitentry 239 if (i < entry_count) { 240 section = entries_address_ascending[i]->section; 241 rc = fill_text_section_content(section, 242 i, entry_count - 1); 243 } 244out: 245 return rc; 246} 247 248 249/* create the elf file */ 250bfd * open_elf(char const * filename) 251{ 252 bfd * abfd; 253 254 abfd = bfd_openw(filename, dump_bfd_target_name); 255 if (!abfd) { 256 bfd_perror("bfd_openw"); 257 goto error1; 258 } 259 if (bfd_set_format(abfd, bfd_object) == FALSE) { 260 bfd_perror("bfd_set_format"); 261 goto error; 262 } 263 if (bfd_set_arch_mach(abfd, dump_bfd_arch, dump_bfd_mach) == FALSE) { 264 bfd_perror("bfd_set_format"); 265 goto error; 266 } 267 return abfd; 268error: 269 bfd_close(abfd); 270error1: 271 return NULL; 272} 273