Home | History | Annotate | Download | only in opjitconv
      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 */
     27 static 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 	}
     68 out:
     69 	return rc;
     70 }
     71 
     72 /*
     73  * create a new section.
     74  */
     75 asection * 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;
     99 error:
    100 	return NULL;
    101 }
    102 
    103 
    104 /* create a .text section. end_idx: index last jitentry (inclusive!)  */
    105 static 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 */
    133 int 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  */
    147 static 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  */
    184 int 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);
    210 out:
    211 	return rc;
    212 }
    213 
    214 
    215 /* Fill the code content into the sections created by partition_sections() */
    216 int 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 	}
    244 out:
    245 	return rc;
    246 }
    247 
    248 
    249 /* create the elf file */
    250 bfd * 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;
    268 error:
    269 	bfd_close(abfd);
    270 error1:
    271 	return NULL;
    272 }
    273