blob: b90e59fcb114c35506f35e4532b9e80094d50023 [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
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}