• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
fill_symtab(void)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  */
create_section(bfd * abfd,char const * section_name,size_t size,bfd_vma vma,flagword flags)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!)  */
create_text_section(int start_idx,int end_idx)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 */
fill_section_content(bfd * abfd,asection * section,void const * b,file_ptr offset,size_t sz)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  */
fill_text_section_content(asection * section,int start_idx,int end_idx)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  */
partition_sections(void)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() */
fill_sections(void)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 */
open_elf(char const * filename)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