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 void vec_do_reserve(void **data
, size_t *mem_size
, size_t new_size
)
25 if (new_size
> *mem_size
|| new_size
* 2 < *mem_size
) {
26 if (new_size
< *mem_size
* 2)
27 new_size
= *mem_size
* 2;
28 *data
= realloc(*data
, new_size
);
29 assert(new_size
== 0 || *data
!= NULL
);
34 void get_syms(bfd
*abfd
, struct asymbolp_vec
*syms
)
36 long storage_needed
= bfd_get_symtab_upper_bound(abfd
);
37 if (storage_needed
== 0)
39 assert(storage_needed
>= 0);
42 vec_reserve(syms
, storage_needed
);
43 vec_resize(syms
, bfd_canonicalize_symtab(abfd
, syms
->data
));
44 assert(syms
->size
>= 0);
47 struct superbfd
*fetch_superbfd(bfd
*abfd
)
50 if (abfd
->usrdata
!= NULL
)
53 struct superbfd
*sbfd
= malloc(sizeof(*sbfd
));
58 get_syms(abfd
, &sbfd
->syms
);
59 vec_init(&sbfd
->new_syms
);
60 sbfd
->new_supersects
= NULL
;
64 struct supersect
*fetch_supersect(struct superbfd
*sbfd
, asection
*sect
)
67 assert(!bfd_is_const_section(sect
));
68 if (sect
->userdata
!= NULL
)
69 return sect
->userdata
;
71 struct supersect
*new = malloc(sizeof(*new));
76 new->name
= sect
->name
;
77 new->flags
= bfd_get_section_flags(sbfd
->abfd
, sect
);
83 vec_init(&new->contents
);
84 vec_resize(&new->contents
, bfd_get_section_size(sect
));
85 assert(bfd_get_section_contents
86 (sbfd
->abfd
, sect
, new->contents
.data
, 0, new->contents
.size
));
87 new->alignment
= bfd_get_section_alignment(sbfd
->abfd
, sect
);
89 vec_init(&new->relocs
);
90 vec_reserve(&new->relocs
, bfd_get_reloc_upper_bound(sbfd
->abfd
, sect
));
91 vec_resize(&new->relocs
,
92 bfd_canonicalize_reloc(sbfd
->abfd
, sect
, new->relocs
.data
,
94 assert(new->relocs
.size
>= 0);
95 vec_init(&new->new_relocs
);
99 for (symp
= sbfd
->syms
.data
; symp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
101 asymbol
*sym
= *symp
;
102 if (sym
->section
== sect
)
103 *vec_grow(&new->syms
, 1) = sym
;
109 struct supersect
*new_supersect(struct superbfd
*sbfd
, const char *name
)
111 struct supersect
*ss
;
112 for (ss
= sbfd
->new_supersects
; ss
!= NULL
; ss
= ss
->next
) {
113 if (strcmp(name
, ss
->name
) == 0)
117 struct supersect
*new = malloc(sizeof(*new));
120 new->next
= sbfd
->new_supersects
;
121 sbfd
->new_supersects
= new;
122 new->flags
= SEC_ALLOC
| SEC_HAS_CONTENTS
| SEC_RELOC
;
127 vec_init(&new->contents
);
129 vec_init(&new->relocs
);
130 vec_init(&new->new_relocs
);
132 new->type
= SS_TYPE_KSPLICE
;
136 void supersect_move(struct supersect
*dest_ss
, struct supersect
*src_ss
)
139 vec_init(&src_ss
->contents
);
140 vec_init(&src_ss
->relocs
);
141 vec_init(&src_ss
->new_relocs
);
142 vec_init(&src_ss
->syms
);
145 void *sect_do_grow(struct supersect
*ss
, size_t n
, size_t size
, int alignment
)
147 if (ss
->alignment
< ffs(alignment
) - 1)
148 ss
->alignment
= ffs(alignment
) - 1;
149 int pad
= align(ss
->contents
.size
, alignment
) - ss
->contents
.size
;
150 void *out
= vec_grow(&ss
->contents
, pad
+ n
* size
);
151 memset(out
, 0, pad
+ n
* size
);
155 static void mod_relocs(struct arelentp_vec
*dest_relocs
,
156 struct arelentp_vec
*src_relocs
,
157 bfd_size_type start
, bfd_size_type end
,
161 for (relocp
= src_relocs
->data
;
162 relocp
< src_relocs
->data
+ src_relocs
->size
; relocp
++) {
163 if ((*relocp
)->address
>= start
&& (*relocp
)->address
< end
) {
164 arelent
*reloc
= malloc(sizeof(*reloc
));
165 assert(reloc
!= NULL
);
167 reloc
->address
+= mod
;
168 *vec_grow(dest_relocs
, 1) = reloc
;
173 static void mod_symbols(struct asymbolp_vec
*dest_syms
,
174 struct asymbolp_vec
*src_syms
,
175 bfd_size_type start
, bfd_size_type end
,
179 for (symp
= src_syms
->data
;
180 symp
< src_syms
->data
+ src_syms
->size
; symp
++) {
181 /* must mutate symbols in-place since there are pointers
182 to them in relocations elsewhere */
183 asymbol
*sym
= *symp
;
184 if (sym
->value
>= start
&& sym
->value
< end
) {
186 *vec_grow(dest_syms
, 1) = sym
;
191 void sect_do_copy(struct supersect
*dest_ss
, void *dest
,
192 struct supersect
*src_ss
, const void *src
, size_t n
)
194 memcpy(dest
, src
, n
);
195 bfd_size_type start
= src
- src_ss
->contents
.data
;
196 bfd_size_type end
= start
+ n
;
197 bfd_size_type mod
= (dest
- dest_ss
->contents
.data
) -
198 (src
- src_ss
->contents
.data
);
199 mod_relocs(&dest_ss
->relocs
, &src_ss
->relocs
, start
, end
, mod
);
200 mod_relocs(&dest_ss
->new_relocs
, &src_ss
->new_relocs
, start
, end
, mod
);
201 mod_symbols(&dest_ss
->syms
, &src_ss
->syms
, start
, end
, mod
);
204 bfd_vma
addr_offset(struct supersect
*ss
, const void *addr
)
206 return (void *)addr
- ss
->contents
.data
;
209 bfd_vma
get_reloc_offset(struct supersect
*ss
, arelent
*reloc
, bool adjust_pc
)
211 int size
= bfd_get_reloc_size(reloc
->howto
);
213 bfd_vma x
= bfd_get(size
* 8, ss
->parent
->abfd
,
214 ss
->contents
.data
+ reloc
->address
);
215 x
&= reloc
->howto
->src_mask
;
216 x
>>= reloc
->howto
->bitpos
;
217 bfd_vma signbit
= reloc
->howto
->dst_mask
>> reloc
->howto
->bitpos
;
218 signbit
&= ~(signbit
>> 1);
219 switch (reloc
->howto
->complain_on_overflow
) {
220 case complain_overflow_signed
:
221 case complain_overflow_bitfield
:
224 case complain_overflow_unsigned
:
229 x
<<= reloc
->howto
->rightshift
;
231 bfd_vma add
= reloc
->addend
;
232 if (reloc
->howto
->pc_relative
) {
233 if (!reloc
->howto
->pcrel_offset
)
234 add
+= reloc
->address
;
241 bfd_vma
read_reloc(struct supersect
*ss
, const void *addr
, size_t size
,
245 bfd_vma val
= bfd_get(size
* 8, ss
->parent
->abfd
, addr
);
246 bfd_vma address
= addr_offset(ss
, addr
);
247 for (relocp
= ss
->relocs
.data
;
248 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
249 arelent
*reloc
= *relocp
;
250 if (reloc
->address
== address
) {
252 *symp
= *reloc
->sym_ptr_ptr
;
253 else if (*reloc
->sym_ptr_ptr
!=
254 bfd_abs_section_ptr
->symbol
)
255 fprintf(stderr
, "warning: unexpected "
256 "non-absolute relocation at %s+%lx\n",
257 ss
->name
, (unsigned long)address
);
258 return get_reloc_offset(ss
, reloc
, false);
262 *symp
= *bfd_abs_section_ptr
->symbol_ptr_ptr
;
266 char *str_pointer(struct supersect
*ss
, void *const *addr
)
269 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
271 assert(asprintf(&str
, "%s+%lx", sym
->name
, (unsigned long)offset
) >= 0);
275 const void *read_pointer(struct supersect
*ss
, void *const *addr
,
276 struct supersect
**data_ssp
)
279 bfd_vma offset
= read_reloc(ss
, addr
, sizeof(*addr
), &sym
);
280 if (bfd_is_abs_section(sym
->section
) && sym
->value
+ offset
== 0)
282 if (bfd_is_const_section(sym
->section
)) {
283 fprintf(stderr
, "warning: unexpected relocation to const "
284 "section at %s+%lx\n", ss
->name
,
285 (unsigned long)addr_offset(ss
, addr
));
288 struct supersect
*data_ss
= fetch_supersect(ss
->parent
, sym
->section
);
289 if (data_ssp
!= NULL
)
291 return data_ss
->contents
.data
+ sym
->value
+ offset
;
294 const char *read_string(struct supersect
*ss
, const char *const *addr
)
296 return read_pointer(ss
, (void *const *)addr
, NULL
);
299 struct caller_search
{
300 struct superbfd
*sbfd
;
302 asection
*calling_section
;
306 void search_for_caller(bfd
*abfd
, asection
*sect
, void *searchptr
)
308 struct caller_search
*search
= searchptr
;
309 struct superbfd
*sbfd
= search
->sbfd
;
310 struct supersect
*ss
= fetch_supersect(sbfd
, sect
);
313 for (relocp
= ss
->relocs
.data
;
314 relocp
< ss
->relocs
.data
+ ss
->relocs
.size
; relocp
++) {
315 asymbol
*rsym
= *(*relocp
)->sym_ptr_ptr
;
316 if (rsym
->section
== search
->sym
->section
&&
317 rsym
->value
+ get_reloc_offset(ss
, *relocp
, true) ==
318 search
->sym
->value
) {
319 if (search
->calling_section
!= sect
)
321 if (search
->calling_section
== NULL
)
322 search
->calling_section
= sect
;
327 static const char *find_caller(struct supersect
*ss
, asymbol
*sym
)
329 struct caller_search search
= {
333 .calling_section
= NULL
,
336 bfd_map_over_sections(ss
->parent
->abfd
, search_for_caller
, &search
);
337 if (search
.count
== 1)
338 return search
.calling_section
->name
;
339 if (search
.count
== 0)
340 return "*no_caller*";
341 return "*multiple_callers*";
344 asymbol
**canonical_symbolp(struct superbfd
*sbfd
, asymbol
*sym
)
347 asymbol
**ret
= NULL
;
348 for (csymp
= sbfd
->syms
.data
; csymp
< sbfd
->syms
.data
+ sbfd
->syms
.size
;
350 asymbol
*csymtemp
= *csymp
;
351 if (bfd_is_const_section(sym
->section
) && sym
== csymtemp
)
353 if ((csymtemp
->flags
& BSF_DEBUGGING
) != 0 ||
354 sym
->section
!= csymtemp
->section
||
355 sym
->value
!= csymtemp
->value
)
357 if ((csymtemp
->flags
& BSF_GLOBAL
) != 0)
365 /* For section symbols of sections containing no symbols, return the
366 section symbol that relocations are generated against */
367 if ((sym
->flags
& BSF_SECTION_SYM
) != 0)
368 return &sym
->section
->symbol
;
372 asymbol
*canonical_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
374 asymbol
**symp
= canonical_symbolp(sbfd
, sym
);
375 return symp
!= NULL
? *symp
: NULL
;
378 char *static_local_symbol(struct superbfd
*sbfd
, asymbol
*sym
)
380 struct supersect
*ss
= fetch_supersect(sbfd
, sym
->section
);
381 if ((sym
->flags
& BSF_LOCAL
) == 0 || (sym
->flags
& BSF_OBJECT
) == 0)
383 char *dot
= strrchr(sym
->name
, '.');
384 if (dot
== NULL
|| dot
[1 + strspn(dot
+ 1, "0123546789")] != '\0')
386 char *basename
= strndup(sym
->name
, dot
- sym
->name
);
388 if (strcmp(basename
, "__func__") == 0 ||
389 strcmp(basename
, "__PRETTY_FUNCTION__") == 0)
390 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
391 (char *)ss
->contents
.data
+ sym
->value
) >= 0);
393 assert(asprintf(&mangled_name
, "%s<%s>", basename
,
394 find_caller(ss
, sym
)) >= 0);
398 char *symbol_label(struct superbfd
*sbfd
, asymbol
*sym
)
400 const char *filename
= sbfd
->abfd
->filename
;
401 char *c
= strstr(filename
, ".KSPLICE");
402 int flen
= (c
== NULL
? strlen(filename
) : c
- filename
);
405 if (bfd_is_und_section(sym
->section
) ||
406 (sym
->flags
& BSF_GLOBAL
) != 0) {
407 label
= strdup(sym
->name
);
408 } else if (bfd_is_const_section(sym
->section
)) {
409 assert(asprintf(&label
, "%s<%.*s>",
410 sym
->name
, flen
, filename
) >= 0);
412 asymbol
*gsym
= canonical_symbol(sbfd
, sym
);
415 assert(asprintf(&label
, "%s+%lx<%.*s>",
417 (unsigned long)sym
->value
,
418 flen
, filename
) >= 0);
419 else if ((gsym
->flags
& BSF_GLOBAL
) != 0)
420 label
= strdup(gsym
->name
);
421 else if (static_local_symbol(sbfd
, gsym
))
422 assert(asprintf(&label
, "%s+%lx<%.*s>",
423 static_local_symbol(sbfd
, gsym
),
424 (unsigned long)sym
->value
,
425 flen
, filename
) >= 0);
427 assert(asprintf(&label
, "%s<%.*s>",
428 gsym
->name
, flen
, filename
) >= 0);