Imported Upstream version 0.9.8
[platform/upstream/oprofile.git] / opjitconv / create_bfd.c
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 }