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 assert(!bfd_is_const_section(sect
));
71 if (sect
->userdata
!= NULL
)
72 return sect
->userdata
;
74 struct supersect
*new = malloc(sizeof(*new));
79 new->name
= sect
->name
;
80 new->flags
= bfd_get_section_flags(sbfd
->abfd
, sect
);
86 vec_init(&new->contents
);
87 vec_resize(&new->contents
, bfd_get_section_size(sect
));
88 assert(bfd_get_section_contents
89 (sbfd
->abfd
, sect
, new->contents
.data
, 0, new->contents
.size
));
90 new->alignment
= bfd_get_section_alignment(sbfd
->abfd
, sect
);
92 vec_init(&new->relocs
);
93 vec_reserve(&new->relocs
, bfd_get_reloc_upper_bound(sbfd
->abfd
, sect
));
94 vec_resize(&new->relocs
,
95 bfd_canonicalize_reloc(sbfd
->abfd
, sect
, new->relocs
.data
,
97 assert(new->relocs
.size
>= 0);
98 vec_init(&new->new_relocs
);
100 vec_init(&new->syms
);
102 for (symp
= sbfd
->syms
.data
; symp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
104 asymbol
*sym
= *symp
;
105 if (sym
->section
== sect
)
106 *vec_grow(&new->syms
, 1) = sym
;
112 struct supersect
*new_supersect(struct superbfd
*sbfd
, const char *name
)
114 struct supersect
*ss
;
115 for (ss
= sbfd
->new_supersects
; ss
!= NULL
; ss
= ss
->next
) {
116 if (strcmp(name
, ss
->name
) == 0)
120 struct supersect
*new = malloc(sizeof(*new));
123 new->next
= sbfd
->new_supersects
;
124 sbfd
->new_supersects
= new;
125 new->flags
= SEC_ALLOC
| SEC_HAS_CONTENTS
| SEC_RELOC
;
130 vec_init(&new->contents
);
132 vec_init(&new->relocs
);
133 vec_init(&new->new_relocs
);
135 new->type
= SS_TYPE_KSPLICE
;
139 void supersect_move(struct supersect
*dest_ss
, struct supersect
*src_ss
)
142 vec_init(&src_ss
->contents
);
143 vec_init(&src_ss
->relocs
);
144 vec_init(&src_ss
->new_relocs
);
145 vec_init(&src_ss
->syms
);
148 void *sect_do_grow(struct supersect
*ss
, size_t n
, size_t size
, int alignment
)
150 if (ss
->alignment
< ffs(alignment
) - 1)
151 ss
->alignment
= ffs(alignment
) - 1;
152 int pad
= align(ss
->contents
.size
, alignment
) - ss
->contents
.size
;
153 void *out
= vec_grow(&ss
->contents
, pad
+ n
* size
);
154 memset(out
, 0, pad
+ n
* size
);
158 static void mod_relocs(struct arelentp_vec
*dest_relocs
,
159 struct arelentp_vec
*src_relocs
,
160 bfd_size_type start
, bfd_size_type end
,
164 for (relocp
= src_relocs
->data
;
165 relocp
< src_relocs
->data
+ src_relocs
->size
; relocp
++) {
166 if ((*relocp
)->address
>= start
&& (*relocp
)->address
< end
) {
167 arelent
*reloc
= malloc(sizeof(*reloc
));
168 assert(reloc
!= NULL
);
170 reloc
->address
+= mod
;
171 *vec_grow(dest_relocs
, 1) = reloc
;
176 static void mod_symbols(struct asymbolp_vec
*dest_syms
,
177 struct asymbolp_vec
*src_syms
,
178 bfd_size_type start
, bfd_size_type end
,
182 for (symp
= src_syms
->data
;
183 symp
< src_syms
->data
+ src_syms
->size
; symp
++) {
184 /* must mutate symbols in-place since there are pointers
185 to them in relocations elsewhere */
186 asymbol
*sym
= *symp
;
187 if (sym
->value
>= start
&& sym
->value
< end
) {
189 *vec_grow(dest_syms
, 1) = sym
;
194 void sect_do_copy(struct supersect
*dest_ss
, void *dest
,
195 struct supersect
*src_ss
, const void *src
, size_t n
)
197 memcpy(dest
, src
, n
);
198 bfd_size_type start
= src
- src_ss
->contents
.data
;
199 bfd_size_type end
= start
+ n
;
200 bfd_size_type mod
= (dest
- dest_ss
->contents
.data
) -
201 (src
- src_ss
->contents
.data
);
202 mod_relocs(&dest_ss
->relocs
, &src_ss
->relocs
, start
, end
, mod
);
203 mod_relocs(&dest_ss
->new_relocs
, &src_ss
->new_relocs
, start
, end
, mod
);
204 mod_symbols(&dest_ss
->syms
, &src_ss
->syms
, start
, end
, mod
);
207 bfd_vma
addr_offset(struct supersect
*ss
, const void *addr
)
209 return (void *)addr
- ss
->contents
.data
;
212 bfd_vma
get_reloc_offset(struct supersect
*ss
, arelent
*reloc
, bool adjust_pc
)
214 int size
= bfd_get_reloc_size(reloc
->howto
);
216 bfd_vma x
= bfd_get(size
* 8, ss
->parent
->abfd
,
217 ss
->contents
.data
+ reloc
->address
);
218 x
&= reloc
->howto
->src_mask
;
219 x
>>= reloc
->howto
->bitpos
;
220 bfd_vma signbit
= reloc
->howto
->dst_mask
>> reloc
->howto
->bitpos
;
221 signbit
&= ~(signbit
>> 1);
222 switch (reloc
->howto
->complain_on_overflow
) {
223 case complain_overflow_signed
:
224 case complain_overflow_bitfield
:
227 case complain_overflow_unsigned
:
232 x
<<= reloc
->howto
->rightshift
;
234 bfd_vma add
= reloc
->addend
;
235 if (reloc
->howto
->pc_relative
) {
236 if (!reloc
->howto
->pcrel_offset
)
237 add
+= reloc
->address
;
244 bfd_vma
read_reloc(struct supersect
*ss
, const void *addr
, size_t size
,
248 bfd_vma val
= bfd_get(size
* 8, ss
->parent
->abfd
, addr
);
249 bfd_vma address
= addr_offset(ss
, addr
);
250 for (relocp
= ss
->relocs
.data
;
251 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
252 arelent
*reloc
= *relocp
;
253 if (reloc
->address
== address
) {
255 *symp
= *reloc
->sym_ptr_ptr
;
256 else if (*reloc
->sym_ptr_ptr
!=
257 bfd_abs_section_ptr
->symbol
)
258 fprintf(stderr
, "warning: unexpected "
259 "non-absolute relocation at %s+%lx\n",
260 ss
->name
, (unsigned long)address
);
261 return get_reloc_offset(ss
, reloc
, false);
265 *symp
= *bfd_abs_section_ptr
->symbol_ptr_ptr
;
269 char *str_pointer(struct supersect
*ss
, void *const *addr
)
272 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
274 assert(asprintf(&str
, "%s+%lx", sym
->name
, (unsigned long)offset
) >= 0);
278 const void *read_pointer(struct supersect
*ss
, void *const *addr
,
279 struct supersect
**data_ssp
)
282 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
283 if (bfd_is_abs_section(sym
->section
) && sym
->value
+ offset
== 0)
285 if (bfd_is_const_section(sym
->section
)) {
286 fprintf(stderr
, "warning: unexpected relocation to const "
287 "section at %s+%lx\n", ss
->name
,
288 (unsigned long)addr_offset(ss
, addr
));
291 struct supersect
*data_ss
= fetch_supersect(ss
->parent
, sym
->section
);
292 if (data_ssp
!= NULL
)
294 return data_ss
->contents
.data
+ sym
->value
+ offset
;
297 const char *read_string(struct supersect
*ss
, const char *const *addr
)
299 return read_pointer(ss
, (void *const *)addr
, NULL
);
302 struct caller_search
{
303 struct superbfd
*sbfd
;
305 asection
*calling_section
;
309 void search_for_caller(bfd
*abfd
, asection
*sect
, void *searchptr
)
311 struct caller_search
*search
= searchptr
;
312 struct superbfd
*sbfd
= search
->sbfd
;
313 struct supersect
*ss
= fetch_supersect(sbfd
, sect
);
316 for (relocp
= ss
->relocs
.data
;
317 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
318 asymbol
*rsym
= *(*relocp
)->sym_ptr_ptr
;
319 if (rsym
->section
== search
->sym
->section
&&
320 rsym
->value
+ get_reloc_offset(ss
, *relocp
, true) ==
321 search
->sym
->value
) {
322 if (search
->calling_section
!= sect
)
324 if (search
->calling_section
== NULL
)
325 search
->calling_section
= sect
;
330 static const char *find_caller(struct supersect
*ss
, asymbol
*sym
)
332 struct caller_search search
= {
336 .calling_section
= NULL
,
339 bfd_map_over_sections(ss
->parent
->abfd
, search_for_caller
, &search
);
340 if (search
.count
== 1)
341 return search
.calling_section
->name
;
342 if (search
.count
== 0)
343 return "*no_caller*";
344 return "*multiple_callers*";
347 asymbol
**canonical_symbolp(struct superbfd
*sbfd
, asymbol
*sym
)
350 asymbol
**ret
= NULL
;
351 for (csymp
= sbfd
->syms
.data
; csymp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
353 asymbol
*csymtemp
= *csymp
;
354 if (bfd_is_const_section(sym
->section
) && sym
== csymtemp
)
356 if ((csymtemp
->flags
& BSF_DEBUGGING
) != 0 ||
357 sym
->section
!= csymtemp
->section
||
358 sym
->value
!= csymtemp
->value
)
360 if ((csymtemp
->flags
& BSF_GLOBAL
) != 0)
368 /* For section symbols of sections containing no symbols, return the
369 section symbol that relocations are generated against */
370 if ((sym
->flags
& BSF_SECTION_SYM
) != 0)
371 return &sym
->section
->symbol
;
375 asymbol
*canonical_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
377 asymbol
**symp
= canonical_symbolp(sbfd
, sym
);
378 return symp
!= NULL
? *symp
: NULL
;
381 const char *static_local_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
383 struct supersect
*ss
= fetch_supersect(sbfd
, sym
->section
);
384 if ((sym
->flags
& BSF_LOCAL
) == 0 || (sym
->flags
& BSF_OBJECT
) == 0)
386 char *dot
= strrchr(sym
->name
, '.');
387 if (dot
== NULL
|| dot
[1 + strspn(dot
+ 1, "0123546789")] != '\0')
389 char *basename
= strndup(sym
->name
, dot
- sym
->name
);
391 if (strcmp(basename
, "__func__") == 0 ||
392 strcmp(basename
, "__PRETTY_FUNCTION__") == 0)
393 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
394 (char *)ss
->contents
.data
+ sym
->value
) >= 0);
396 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
397 find_caller(ss
, sym
)) >= 0);
401 static char *symbol_label(struct superbfd
*sbfd
, asymbol
*sym
)
403 const char *filename
= sbfd
->abfd
->filename
;
404 char *c
= strstr(filename
, ".KSPLICE");
405 int flen
= (c
== NULL
? strlen(filename
) : c
- filename
);
408 if (bfd_is_und_section(sym
->section
) ||
409 (sym
->flags
& BSF_GLOBAL
) != 0) {
410 label
= strdup(sym
->name
);
411 } else if (bfd_is_const_section(sym
->section
)) {
412 assert(asprintf(&label
, "%s<%.*s>",
413 sym
->name
, flen
, filename
) >= 0);
415 asymbol
*gsym
= canonical_symbol(sbfd
, sym
);
418 assert(asprintf(&label
, "%s+%lx<%.*s>",
420 (unsigned long)sym
->value
,
421 flen
, filename
) >= 0);
422 else if ((gsym
->flags
& BSF_GLOBAL
) != 0)
423 label
= strdup(gsym
->name
);
424 else if (static_local_symbol(sbfd
, gsym
))
425 assert(asprintf(&label
, "%s+%lx<%.*s>",
426 static_local_symbol(sbfd
, gsym
),
427 (unsigned long)sym
->value
,
428 flen
, filename
) >= 0);
430 assert(asprintf(&label
, "%s<%.*s>",
431 gsym
->name
, flen
, filename
) >= 0);
437 static void init_label_map(struct superbfd
*sbfd
)
439 vec_init(&sbfd
->maps
);
440 struct label_map
*map
, *map2
;
443 for (symp
= sbfd
->syms
.data
;
444 symp
< sbfd
->syms
.data
+ sbfd
->syms
.size
; symp
++) {
445 asymbol
*csym
= canonical_symbol(sbfd
, *symp
);
448 for (map
= sbfd
->maps
.data
;
449 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
450 if (map
->csym
== csym
)
453 if (map
< sbfd
->maps
.data
+ sbfd
->maps
.size
)
455 map
= vec_grow(&sbfd
->maps
, 1);
459 map
->label
= symbol_label(sbfd
, csym
);
461 for (map
= sbfd
->maps
.data
;
462 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
463 for (map2
= sbfd
->maps
.data
;
464 map2
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map2
++) {
465 if (strcmp(map
->label
, map2
->label
) != 0)
473 for (map
= sbfd
->maps
.data
;
474 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
475 map
->orig_label
= map
->label
;
476 if (map
->count
> 1) {
478 assert(asprintf(&buf
, "%s~%d", map
->label
,
485 const char *label_lookup(struct superbfd
*sbfd
, asymbol
*sym
)
487 struct label_map
*map
;
488 asymbol
*csym
= canonical_symbol(sbfd
, sym
);
489 for (map
= sbfd
->maps
.data
;
490 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
491 if (csym
== map
->csym
)
494 return symbol_label(sbfd
, sym
);
497 void print_label_map(struct superbfd
*sbfd
)
499 struct label_map
*map
;
500 for (map
= sbfd
->maps
.data
;
501 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
502 if (strcmp(map
->orig_label
, map
->label
) == 0)
504 printf(" %s -> %s\n", map
->label
, map
->orig_label
);
508 void label_map_set(struct superbfd
*sbfd
, const char *oldlabel
,
511 struct label_map
*map
;
512 for (map
= sbfd
->maps
.data
;
513 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
514 if (strcmp(map
->orig_label
, oldlabel
) == 0) {
515 if (strcmp(map
->orig_label
, map
->label
) != 0 &&
516 strcmp(map
->label
, label
) != 0)