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
);
138 void supersect_move(struct supersect
*dest_ss
, struct supersect
*src_ss
)
141 vec_init(&src_ss
->contents
);
142 vec_init(&src_ss
->relocs
);
143 vec_init(&src_ss
->new_relocs
);
144 vec_init(&src_ss
->syms
);
147 void *sect_do_grow(struct supersect
*ss
, size_t n
, size_t size
, int alignment
)
149 if (ss
->alignment
< ffs(alignment
) - 1)
150 ss
->alignment
= ffs(alignment
) - 1;
151 int pad
= align(ss
->contents
.size
, alignment
) - ss
->contents
.size
;
152 void *out
= vec_grow(&ss
->contents
, pad
+ n
* size
);
153 memset(out
, 0, pad
+ n
* size
);
157 static void mod_relocs(struct arelentp_vec
*dest_relocs
,
158 struct arelentp_vec
*src_relocs
,
159 bfd_size_type start
, bfd_size_type end
,
163 for (relocp
= src_relocs
->data
;
164 relocp
< src_relocs
->data
+ src_relocs
->size
; relocp
++) {
165 if ((*relocp
)->address
>= start
&& (*relocp
)->address
< end
) {
166 arelent
*reloc
= malloc(sizeof(*reloc
));
167 assert(reloc
!= NULL
);
169 reloc
->address
+= mod
;
170 *vec_grow(dest_relocs
, 1) = reloc
;
175 static void mod_symbols(struct asymbolp_vec
*dest_syms
,
176 struct asymbolp_vec
*src_syms
,
177 bfd_size_type start
, bfd_size_type end
,
181 for (symp
= src_syms
->data
;
182 symp
< src_syms
->data
+ src_syms
->size
; symp
++) {
183 /* must mutate symbols in-place since there are pointers
184 to them in relocations elsewhere */
185 asymbol
*sym
= *symp
;
186 if (sym
->value
>= start
&& sym
->value
< end
) {
188 *vec_grow(dest_syms
, 1) = sym
;
193 void sect_do_copy(struct supersect
*dest_ss
, void *dest
,
194 struct supersect
*src_ss
, const void *src
, size_t n
)
196 memcpy(dest
, src
, n
);
197 bfd_size_type start
= src
- src_ss
->contents
.data
;
198 bfd_size_type end
= start
+ n
;
199 bfd_size_type mod
= (dest
- dest_ss
->contents
.data
) -
200 (src
- src_ss
->contents
.data
);
201 mod_relocs(&dest_ss
->relocs
, &src_ss
->relocs
, start
, end
, mod
);
202 mod_relocs(&dest_ss
->new_relocs
, &src_ss
->new_relocs
, start
, end
, mod
);
203 mod_symbols(&dest_ss
->syms
, &src_ss
->syms
, start
, end
, mod
);
206 bfd_vma
addr_offset(struct supersect
*ss
, const void *addr
)
208 return (void *)addr
- ss
->contents
.data
;
211 bfd_vma
get_reloc_offset(struct supersect
*ss
, arelent
*reloc
, bool adjust_pc
)
213 int size
= bfd_get_reloc_size(reloc
->howto
);
215 bfd_vma x
= bfd_get(size
* 8, ss
->parent
->abfd
,
216 ss
->contents
.data
+ reloc
->address
);
217 x
&= reloc
->howto
->src_mask
;
218 x
>>= reloc
->howto
->bitpos
;
219 bfd_vma signbit
= reloc
->howto
->dst_mask
>> reloc
->howto
->bitpos
;
220 signbit
&= ~(signbit
>> 1);
221 switch (reloc
->howto
->complain_on_overflow
) {
222 case complain_overflow_signed
:
223 case complain_overflow_bitfield
:
226 case complain_overflow_unsigned
:
231 x
<<= reloc
->howto
->rightshift
;
233 bfd_vma add
= reloc
->addend
;
234 if (reloc
->howto
->pc_relative
) {
235 if (!reloc
->howto
->pcrel_offset
)
236 add
+= reloc
->address
;
243 bfd_vma
read_reloc(struct supersect
*ss
, const void *addr
, size_t size
,
247 bfd_vma val
= bfd_get(size
* 8, ss
->parent
->abfd
, addr
);
248 bfd_vma address
= addr_offset(ss
, addr
);
249 for (relocp
= ss
->relocs
.data
;
250 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
251 arelent
*reloc
= *relocp
;
252 if (reloc
->address
== address
) {
254 *symp
= *reloc
->sym_ptr_ptr
;
255 else if (*reloc
->sym_ptr_ptr
!=
256 bfd_abs_section_ptr
->symbol
)
257 fprintf(stderr
, "warning: unexpected "
258 "non-absolute relocation at %s+%lx\n",
259 ss
->name
, (unsigned long)address
);
260 return get_reloc_offset(ss
, reloc
, false);
264 *symp
= *bfd_abs_section_ptr
->symbol_ptr_ptr
;
268 char *str_pointer(struct supersect
*ss
, void *const *addr
)
271 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
273 assert(asprintf(&str
, "%s+%lx", sym
->name
, (unsigned long)offset
) >= 0);
277 const void *read_pointer(struct supersect
*ss
, void *const *addr
,
278 struct supersect
**data_ssp
)
281 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
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", ss
->name
,
287 (unsigned long)addr_offset(ss
, addr
));
290 struct supersect
*data_ss
= fetch_supersect(ss
->parent
, sym
->section
);
291 if (data_ssp
!= NULL
)
293 return data_ss
->contents
.data
+ sym
->value
+ offset
;
296 const char *read_string(struct supersect
*ss
, const char *const *addr
)
298 return read_pointer(ss
, (void *const *)addr
, NULL
);
301 struct caller_search
{
302 struct superbfd
*sbfd
;
304 asection
*calling_section
;
308 void search_for_caller(bfd
*abfd
, asection
*sect
, void *searchptr
)
310 struct caller_search
*search
= searchptr
;
311 struct superbfd
*sbfd
= search
->sbfd
;
312 struct supersect
*ss
= fetch_supersect(sbfd
, sect
);
315 for (relocp
= ss
->relocs
.data
;
316 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
317 asymbol
*rsym
= *(*relocp
)->sym_ptr_ptr
;
318 if (rsym
->section
== search
->sym
->section
&&
319 rsym
->value
+ get_reloc_offset(ss
, *relocp
, true) ==
320 search
->sym
->value
) {
321 if (search
->calling_section
!= sect
)
323 if (search
->calling_section
== NULL
)
324 search
->calling_section
= sect
;
329 static const char *find_caller(struct supersect
*ss
, asymbol
*sym
)
331 struct caller_search search
= {
335 .calling_section
= NULL
,
338 bfd_map_over_sections(ss
->parent
->abfd
, search_for_caller
, &search
);
339 if (search
.count
== 1)
340 return search
.calling_section
->name
;
341 if (search
.count
== 0)
342 return "*no_caller*";
343 return "*multiple_callers*";
346 asymbol
**canonical_symbolp(struct superbfd
*sbfd
, asymbol
*sym
)
349 asymbol
**ret
= NULL
;
350 for (csymp
= sbfd
->syms
.data
; csymp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
352 asymbol
*csymtemp
= *csymp
;
353 if (bfd_is_const_section(sym
->section
) && sym
== csymtemp
)
355 if ((csymtemp
->flags
& BSF_DEBUGGING
) != 0 ||
356 sym
->section
!= csymtemp
->section
||
357 sym
->value
!= csymtemp
->value
)
359 if ((csymtemp
->flags
& BSF_GLOBAL
) != 0)
367 /* For section symbols of sections containing no symbols, return the
368 section symbol that relocations are generated against */
369 if ((sym
->flags
& BSF_SECTION_SYM
) != 0)
370 return &sym
->section
->symbol
;
374 asymbol
*canonical_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
376 asymbol
**symp
= canonical_symbolp(sbfd
, sym
);
377 return symp
!= NULL
? *symp
: NULL
;
380 const char *static_local_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
382 struct supersect
*ss
= fetch_supersect(sbfd
, sym
->section
);
383 if ((sym
->flags
& BSF_LOCAL
) == 0 || (sym
->flags
& BSF_OBJECT
) == 0)
385 char *dot
= strrchr(sym
->name
, '.');
386 if (dot
== NULL
|| dot
[1 + strspn(dot
+ 1, "0123546789")] != '\0')
388 char *basename
= strndup(sym
->name
, dot
- sym
->name
);
390 if (strcmp(basename
, "__func__") == 0 ||
391 strcmp(basename
, "__PRETTY_FUNCTION__") == 0)
392 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
393 (char *)ss
->contents
.data
+ sym
->value
) >= 0);
395 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
396 find_caller(ss
, sym
)) >= 0);
400 static char *symbol_label(struct superbfd
*sbfd
, asymbol
*sym
)
402 const char *filename
= sbfd
->abfd
->filename
;
403 char *c
= strstr(filename
, ".KSPLICE");
404 int flen
= (c
== NULL
? strlen(filename
) : c
- filename
);
407 if (bfd_is_und_section(sym
->section
) ||
408 (sym
->flags
& BSF_GLOBAL
) != 0) {
409 label
= strdup(sym
->name
);
410 } else if (bfd_is_const_section(sym
->section
)) {
411 assert(asprintf(&label
, "%s<%.*s>",
412 sym
->name
, flen
, filename
) >= 0);
414 asymbol
*gsym
= canonical_symbol(sbfd
, sym
);
417 assert(asprintf(&label
, "%s+%lx<%.*s>",
419 (unsigned long)sym
->value
,
420 flen
, filename
) >= 0);
421 else if ((gsym
->flags
& BSF_GLOBAL
) != 0)
422 label
= strdup(gsym
->name
);
423 else if (static_local_symbol(sbfd
, gsym
))
424 assert(asprintf(&label
, "%s+%lx<%.*s>",
425 static_local_symbol(sbfd
, gsym
),
426 (unsigned long)sym
->value
,
427 flen
, filename
) >= 0);
429 assert(asprintf(&label
, "%s<%.*s>",
430 gsym
->name
, flen
, filename
) >= 0);
436 static void init_label_map(struct superbfd
*sbfd
)
438 vec_init(&sbfd
->maps
);
439 struct label_map
*map
, *map2
;
442 for (symp
= sbfd
->syms
.data
;
443 symp
< sbfd
->syms
.data
+ sbfd
->syms
.size
; symp
++) {
444 asymbol
*csym
= canonical_symbol(sbfd
, *symp
);
447 for (map
= sbfd
->maps
.data
;
448 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
449 if (map
->csym
== csym
)
452 if (map
< sbfd
->maps
.data
+ sbfd
->maps
.size
)
454 map
= vec_grow(&sbfd
->maps
, 1);
458 map
->label
= symbol_label(sbfd
, csym
);
460 for (map
= sbfd
->maps
.data
;
461 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
462 for (map2
= sbfd
->maps
.data
;
463 map2
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map2
++) {
464 if (strcmp(map
->label
, map2
->label
) != 0)
472 for (map
= sbfd
->maps
.data
;
473 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
474 map
->orig_label
= map
->label
;
475 if (map
->count
> 1) {
477 assert(asprintf(&buf
, "%s~%d", map
->label
,
484 const char *label_lookup(struct superbfd
*sbfd
, asymbol
*sym
)
486 struct label_map
*map
;
487 asymbol
*csym
= canonical_symbol(sbfd
, sym
);
488 for (map
= sbfd
->maps
.data
;
489 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
490 if (csym
== map
->csym
)
493 return symbol_label(sbfd
, sym
);
496 void print_label_map(struct superbfd
*sbfd
)
498 struct label_map
*map
;
499 for (map
= sbfd
->maps
.data
;
500 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
501 if (strcmp(map
->orig_label
, map
->label
) == 0)
503 printf(" %s -> %s\n", map
->label
, map
->orig_label
);
507 void label_map_set(struct superbfd
*sbfd
, const char *oldlabel
,
510 struct label_map
*map
;
511 for (map
= sbfd
->maps
.data
;
512 map
< sbfd
->maps
.data
+ sbfd
->maps
.size
; map
++) {
513 if (strcmp(map
->orig_label
, oldlabel
) == 0) {
514 if (strcmp(map
->orig_label
, map
->label
) != 0 &&
515 strcmp(map
->label
, label
) != 0)