1 /* Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
2 * Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
3 * Tim Abbott <tabbott@mit.edu>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20 #include "objcommon.h"
23 static void init_label_map(struct superbfd
*sbfd
);
25 void vec_do_reserve(void **data
, size_t *mem_size
, size_t new_size
)
27 if (new_size
> *mem_size
|| new_size
* 2 < *mem_size
) {
28 if (new_size
< *mem_size
* 2)
29 new_size
= *mem_size
* 2;
30 *data
= realloc(*data
, new_size
);
31 assert(new_size
== 0 || *data
!= NULL
);
36 void get_syms(bfd
*abfd
, struct asymbolp_vec
*syms
)
38 long storage_needed
= bfd_get_symtab_upper_bound(abfd
);
39 if (storage_needed
== 0)
41 assert(storage_needed
>= 0);
44 vec_reserve(syms
, storage_needed
);
45 vec_resize(syms
, bfd_canonicalize_symtab(abfd
, syms
->data
));
46 assert(syms
->size
>= 0);
49 struct superbfd
*fetch_superbfd(bfd
*abfd
)
52 if (abfd
->usrdata
!= NULL
)
55 struct superbfd
*sbfd
= malloc(sizeof(*sbfd
));
60 get_syms(abfd
, &sbfd
->syms
);
61 vec_init(&sbfd
->new_syms
);
62 sbfd
->new_supersects
= NULL
;
67 struct supersect
*fetch_supersect(struct superbfd
*sbfd
, asection
*sect
)
70 if (sect
->userdata
!= NULL
)
71 return sect
->userdata
;
73 struct supersect
*new = malloc(sizeof(*new));
78 new->name
= sect
->name
;
79 new->flags
= bfd_get_section_flags(sbfd
->abfd
, sect
);
85 vec_init(&new->contents
);
86 vec_resize(&new->contents
, bfd_get_section_size(sect
));
87 assert(bfd_get_section_contents
88 (sbfd
->abfd
, sect
, new->contents
.data
, 0, new->contents
.size
));
89 new->alignment
= bfd_get_section_alignment(sbfd
->abfd
, sect
);
91 vec_init(&new->relocs
);
92 vec_reserve(&new->relocs
, bfd_get_reloc_upper_bound(sbfd
->abfd
, sect
));
93 vec_resize(&new->relocs
,
94 bfd_canonicalize_reloc(sbfd
->abfd
, sect
, new->relocs
.data
,
96 assert(new->relocs
.size
>= 0);
97 vec_init(&new->new_relocs
);
101 for (symp
= sbfd
->syms
.data
; symp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
103 asymbol
*sym
= *symp
;
104 if (sym
->section
== sect
)
105 *vec_grow(&new->syms
, 1) = sym
;
111 struct supersect
*new_supersect(struct superbfd
*sbfd
, const char *name
)
113 struct supersect
*ss
;
114 for (ss
= sbfd
->new_supersects
; ss
!= NULL
; ss
= ss
->next
) {
115 if (strcmp(name
, ss
->name
) == 0)
119 struct supersect
*new = malloc(sizeof(*new));
122 new->next
= sbfd
->new_supersects
;
123 sbfd
->new_supersects
= new;
124 new->flags
= SEC_ALLOC
| SEC_HAS_CONTENTS
| SEC_RELOC
;
129 vec_init(&new->contents
);
131 vec_init(&new->relocs
);
132 vec_init(&new->new_relocs
);
137 void supersect_move(struct supersect
*dest_ss
, struct supersect
*src_ss
)
140 vec_init(&src_ss
->contents
);
141 vec_init(&src_ss
->relocs
);
142 vec_init(&src_ss
->new_relocs
);
143 vec_init(&src_ss
->syms
);
146 void *sect_do_grow(struct supersect
*ss
, size_t n
, size_t size
, int alignment
)
148 if (ss
->alignment
< ffs(alignment
) - 1)
149 ss
->alignment
= ffs(alignment
) - 1;
150 int pad
= align(ss
->contents
.size
, alignment
) - ss
->contents
.size
;
151 void *out
= vec_grow(&ss
->contents
, pad
+ n
* size
);
152 memset(out
, 0, pad
+ n
* size
);
156 static void mod_relocs(struct arelentp_vec
*dest_relocs
,
157 struct arelentp_vec
*src_relocs
,
158 bfd_size_type start
, bfd_size_type end
,
162 for (relocp
= src_relocs
->data
;
163 relocp
< src_relocs
->data
+ src_relocs
->size
; relocp
++) {
164 if ((*relocp
)->address
>= start
&& (*relocp
)->address
< end
) {
165 arelent
*reloc
= malloc(sizeof(*reloc
));
166 assert(reloc
!= NULL
);
168 reloc
->address
+= mod
;
169 *vec_grow(dest_relocs
, 1) = reloc
;
174 static void mod_symbols(struct asymbolp_vec
*dest_syms
,
175 struct asymbolp_vec
*src_syms
,
176 bfd_size_type start
, bfd_size_type end
,
180 for (symp
= src_syms
->data
;
181 symp
< src_syms
->data
+ src_syms
->size
; symp
++) {
182 /* must mutate symbols in-place since there are pointers
183 to them in relocations elsewhere */
184 asymbol
*sym
= *symp
;
185 if (sym
->value
>= start
&& sym
->value
< end
) {
187 *vec_grow(dest_syms
, 1) = sym
;
192 void sect_do_copy(struct supersect
*dest_ss
, void *dest
,
193 struct supersect
*src_ss
, const void *src
, size_t n
)
195 memcpy(dest
, src
, n
);
196 bfd_size_type start
= src
- src_ss
->contents
.data
;
197 bfd_size_type end
= start
+ n
;
198 bfd_size_type mod
= (dest
- dest_ss
->contents
.data
) -
199 (src
- src_ss
->contents
.data
);
200 mod_relocs(&dest_ss
->relocs
, &src_ss
->relocs
, start
, end
, mod
);
201 mod_relocs(&dest_ss
->new_relocs
, &src_ss
->new_relocs
, start
, end
, mod
);
202 mod_symbols(&dest_ss
->syms
, &src_ss
->syms
, start
, end
, mod
);
205 bfd_vma
addr_offset(struct supersect
*ss
, const void *addr
)
207 return (void *)addr
- ss
->contents
.data
;
210 bfd_vma
get_reloc_offset(struct supersect
*ss
, arelent
*reloc
, bool adjust_pc
)
212 int size
= bfd_get_reloc_size(reloc
->howto
);
214 bfd_vma x
= bfd_get(size
* 8, ss
->parent
->abfd
,
215 ss
->contents
.data
+ reloc
->address
);
216 x
&= reloc
->howto
->src_mask
;
217 x
>>= reloc
->howto
->bitpos
;
218 bfd_vma signbit
= reloc
->howto
->dst_mask
>> reloc
->howto
->bitpos
;
219 signbit
&= ~(signbit
>> 1);
220 switch (reloc
->howto
->complain_on_overflow
) {
221 case complain_overflow_signed
:
222 case complain_overflow_bitfield
:
225 case complain_overflow_unsigned
:
230 x
<<= reloc
->howto
->rightshift
;
232 bfd_vma add
= reloc
->addend
;
233 if (reloc
->howto
->pc_relative
) {
234 if (!reloc
->howto
->pcrel_offset
)
235 add
+= reloc
->address
;
242 bfd_vma
read_reloc(struct supersect
*ss
, const void *addr
, size_t size
,
246 bfd_vma val
= bfd_get(size
* 8, ss
->parent
->abfd
, addr
);
247 bfd_vma address
= addr_offset(ss
, addr
);
248 for (relocp
= ss
->relocs
.data
;
249 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
250 arelent
*reloc
= *relocp
;
251 if (reloc
->address
== address
) {
253 *symp
= *reloc
->sym_ptr_ptr
;
254 else if (*reloc
->sym_ptr_ptr
!=
255 bfd_abs_section_ptr
->symbol
)
256 fprintf(stderr
, "warning: unexpected "
257 "non-absolute relocation at %s+%lx\n",
258 ss
->name
, (unsigned long)address
);
259 return get_reloc_offset(ss
, reloc
, false);
263 *symp
= *bfd_abs_section_ptr
->symbol_ptr_ptr
;
267 char *str_pointer(struct supersect
*ss
, void *const *addr
)
270 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
272 assert(asprintf(&str
, "%s+%lx", sym
->name
, (unsigned long)offset
) >= 0);
276 const void *read_pointer(struct supersect
*ss
, void *const *addr
,
277 struct supersect
**data_ssp
)
280 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
281 struct supersect
*data_ss
= fetch_supersect(ss
->parent
, sym
->section
);
282 if (bfd_is_abs_section(sym
->section
) && sym
->value
+ offset
== 0)
284 if (bfd_is_const_section(sym
->section
)) {
285 fprintf(stderr
, "warning: unexpected relocation to const "
286 "section at %s+%lx\n", data_ss
->name
,
287 (unsigned long)addr_offset(data_ss
, addr
));
290 if (data_ssp
!= NULL
)
292 return data_ss
->contents
.data
+ sym
->value
+ offset
;
295 const char *read_string(struct supersect
*ss
, const char *const *addr
)
297 return read_pointer(ss
, (void *const *)addr
, NULL
);
300 struct caller_search
{
301 struct superbfd
*sbfd
;
303 asection
*calling_section
;
307 void search_for_caller(bfd
*abfd
, asection
*sect
, void *searchptr
)
309 struct caller_search
*search
= searchptr
;
310 struct superbfd
*sbfd
= search
->sbfd
;
311 struct supersect
*ss
= fetch_supersect(sbfd
, sect
);
314 for (relocp
= ss
->relocs
.data
;
315 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
316 asymbol
*rsym
= *(*relocp
)->sym_ptr_ptr
;
317 if (rsym
->section
== search
->sym
->section
&&
318 rsym
->value
+ get_reloc_offset(ss
, *relocp
, true) ==
319 search
->sym
->value
) {
320 if (search
->calling_section
!= sect
)
322 if (search
->calling_section
== NULL
)
323 search
->calling_section
= sect
;
328 static const char *find_caller(struct supersect
*ss
, asymbol
*sym
)
330 struct caller_search search
= {
334 .calling_section
= NULL
,
337 bfd_map_over_sections(ss
->parent
->abfd
, search_for_caller
, &search
);
338 if (search
.count
== 1)
339 return search
.calling_section
->name
;
340 if (search
.count
== 0)
341 return "*no_caller*";
342 return "*multiple_callers*";
345 asymbol
**canonical_symbolp(struct superbfd
*sbfd
, asymbol
*sym
)
348 asymbol
**ret
= NULL
;
349 for (csymp
= sbfd
->syms
.data
; csymp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
351 asymbol
*csymtemp
= *csymp
;
352 if (bfd_is_const_section(sym
->section
) && sym
== csymtemp
)
354 if ((csymtemp
->flags
& BSF_DEBUGGING
) != 0 ||
355 sym
->section
!= csymtemp
->section
||
356 sym
->value
!= csymtemp
->value
)
358 if ((csymtemp
->flags
& BSF_GLOBAL
) != 0)
366 /* For section symbols of sections containing no symbols, return the
367 section symbol that relocations are generated against */
368 if ((sym
->flags
& BSF_SECTION_SYM
) != 0)
369 return &sym
->section
->symbol
;
373 asymbol
*canonical_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
375 asymbol
**symp
= canonical_symbolp(sbfd
, sym
);
376 return symp
!= NULL
? *symp
: NULL
;
379 const char *static_local_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
381 struct supersect
*ss
= fetch_supersect(sbfd
, sym
->section
);
382 if ((sym
->flags
& BSF_LOCAL
) == 0 || (sym
->flags
& BSF_OBJECT
) == 0)
384 char *dot
= strrchr(sym
->name
, '.');
385 if (dot
== NULL
|| dot
[1 + strspn(dot
+ 1, "0123546789")] != '\0')
387 char *basename
= strndup(sym
->name
, dot
- sym
->name
);
389 if (strcmp(basename
, "__func__") == 0 ||
390 strcmp(basename
, "__PRETTY_FUNCTION__") == 0)
391 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
392 (char *)ss
->contents
.data
+ sym
->value
) >= 0);
394 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
395 find_caller(ss
, sym
)) >= 0);
399 static char *symbol_label(struct superbfd
*sbfd
, asymbol
*sym
)
401 const char *filename
= sbfd
->abfd
->filename
;
402 char *c
= strstr(filename
, ".KSPLICE");
403 int flen
= (c
== NULL
? strlen(filename
) : c
- filename
);
406 if (bfd_is_und_section(sym
->section
) ||
407 (sym
->flags
& BSF_GLOBAL
) != 0) {
408 label
= strdup(sym
->name
);
409 } else if (bfd_is_const_section(sym
->section
)) {
410 assert(asprintf(&label
, "%s<%.*s>",
411 sym
->name
, flen
, filename
) >= 0);
413 asymbol
*gsym
= canonical_symbol(sbfd
, sym
);
416 assert(asprintf(&label
, "%s+%lx<%.*s>",
418 (unsigned long)sym
->value
,
419 flen
, filename
) >= 0);
420 else if ((gsym
->flags
& BSF_GLOBAL
) != 0)
421 label
= strdup(gsym
->name
);
422 else if (static_local_symbol(sbfd
, gsym
))
423 assert(asprintf(&label
, "%s+%lx<%.*s>",
424 static_local_symbol(sbfd
, gsym
),
425 (unsigned long)sym
->value
,
426 flen
, filename
) >= 0);
428 assert(asprintf(&label
, "%s<%.*s>",
429 gsym
->name
, flen
, filename
) >= 0);
435 static void init_label_map(struct superbfd
*sbfd
)
437 vec_init(&sbfd
->maps
);
438 struct label_map
*map
, *map2
;
441 for (symp
= sbfd
->syms
.data
;
442 symp
< sbfd
->syms
.data
+ sbfd
->syms
.size
; symp
++) {
443 asymbol
*csym
= canonical_symbol(sbfd
, *symp
);
446 for (map
= sbfd
->maps
.data
;
447 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
448 if (map
->csym
== csym
)
451 if (map
< sbfd
->maps
.data
+ sbfd
->maps
.size
)
453 map
= vec_grow(&sbfd
->maps
, 1);
457 map
->label
= symbol_label(sbfd
, csym
);
459 for (map
= sbfd
->maps
.data
;
460 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
461 for (map2
= sbfd
->maps
.data
;
462 map2
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map2
++) {
463 if (strcmp(map
->label
, map2
->label
) != 0)
471 for (map
= sbfd
->maps
.data
;
472 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
473 map
->orig_label
= map
->label
;
474 if (map
->count
> 1) {
476 assert(asprintf(&buf
, "%s~%d", map
->label
,
483 const char *label_lookup(struct superbfd
*sbfd
, asymbol
*sym
)
485 struct label_map
*map
;
486 asymbol
*csym
= canonical_symbol(sbfd
, sym
);
487 for (map
= sbfd
->maps
.data
;
488 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
489 if (csym
== map
->csym
)
492 return symbol_label(sbfd
, sym
);
495 void print_label_map(struct superbfd
*sbfd
)
497 struct label_map
*map
;
498 for (map
= sbfd
->maps
.data
;
499 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
500 if (strcmp(map
->orig_label
, map
->label
) == 0)
502 printf(" %s -> %s\n", map
->label
, map
->orig_label
);
506 void label_map_set(struct superbfd
*sbfd
, const char *oldlabel
,
509 struct label_map
*map
;
510 for (map
= sbfd
->maps
.data
;
511 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
512 if (strcmp(map
->orig_label
, oldlabel
) == 0) {
513 if (strcmp(map
->orig_label
, map
->label
) != 0 &&
514 strcmp(map
->label
, label
) != 0)