Die when fetch_supersect is called on const sections.
[ksplice.git] / objcommon.c
blob67d3dec971ac72d3d95764b67fca958450909468
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
16 * 02110-1301, USA.
19 #define _GNU_SOURCE
20 #include "objcommon.h"
21 #include <stdio.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);
32 *mem_size = new_size;
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)
40 return;
41 assert(storage_needed >= 0);
43 vec_init(syms);
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)
51 assert(abfd != NULL);
52 if (abfd->usrdata != NULL)
53 return abfd->usrdata;
55 struct superbfd *sbfd = malloc(sizeof(*sbfd));
56 assert(sbfd != NULL);
58 abfd->usrdata = sbfd;
59 sbfd->abfd = abfd;
60 get_syms(abfd, &sbfd->syms);
61 vec_init(&sbfd->new_syms);
62 sbfd->new_supersects = NULL;
63 init_label_map(sbfd);
64 return sbfd;
67 struct supersect *fetch_supersect(struct superbfd *sbfd, asection *sect)
69 assert(sect != NULL);
70 assert(!bfd_is_const_section(sect));
71 if (sect->userdata != NULL)
72 return sect->userdata;
74 struct supersect *new = malloc(sizeof(*new));
75 assert(new != NULL);
77 sect->userdata = new;
78 new->parent = sbfd;
79 new->name = sect->name;
80 new->flags = bfd_get_section_flags(sbfd->abfd, sect);
81 new->match = NULL;
82 new->new = false;
83 new->patch = false;
84 new->keep = true;
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,
96 sbfd->syms.data));
97 assert(new->relocs.size >= 0);
98 vec_init(&new->new_relocs);
100 vec_init(&new->syms);
101 asymbol **symp;
102 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
103 symp++) {
104 asymbol *sym = *symp;
105 if (sym->section == sect)
106 *vec_grow(&new->syms, 1) = sym;
109 return new;
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)
117 return ss;
120 struct supersect *new = malloc(sizeof(*new));
121 new->parent = sbfd;
122 new->name = name;
123 new->next = sbfd->new_supersects;
124 sbfd->new_supersects = new;
125 new->flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_RELOC;
126 new->new = false;
127 new->patch = false;
128 new->keep = true;
130 vec_init(&new->contents);
131 new->alignment = 0;
132 vec_init(&new->relocs);
133 vec_init(&new->new_relocs);
135 return new;
138 void supersect_move(struct supersect *dest_ss, struct supersect *src_ss)
140 *dest_ss = *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);
154 return out + pad;
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,
160 bfd_size_type mod)
162 arelent **relocp;
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);
168 *reloc = **relocp;
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,
178 bfd_size_type mod)
180 asymbol **symp;
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) {
187 sym->value += mod;
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:
224 x |= -(x & signbit);
225 break;
226 case complain_overflow_unsigned:
227 break;
228 default:
229 DIE;
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;
237 if (adjust_pc)
238 add += size;
240 return x + add;
243 bfd_vma read_reloc(struct supersect *ss, const void *addr, size_t size,
244 asymbol **symp)
246 arelent **relocp;
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) {
253 if (symp != NULL)
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);
263 if (symp != NULL)
264 *symp = *bfd_abs_section_ptr->symbol_ptr_ptr;
265 return val;
268 char *str_pointer(struct supersect *ss, void *const *addr)
270 asymbol *sym;
271 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
272 char *str;
273 assert(asprintf(&str, "%s+%lx", sym->name, (unsigned long)offset) >= 0);
274 return str;
277 const void *read_pointer(struct supersect *ss, void *const *addr,
278 struct supersect **data_ssp)
280 asymbol *sym;
281 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
282 if (bfd_is_abs_section(sym->section) && sym->value + offset == 0)
283 return NULL;
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));
288 return NULL;
290 struct supersect *data_ss = fetch_supersect(ss->parent, sym->section);
291 if (data_ssp != NULL)
292 *data_ssp = data_ss;
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;
303 asymbol *sym;
304 asection *calling_section;
305 int count;
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);
313 arelent **relocp;
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)
322 search->count++;
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 = {
332 .sym = sym,
333 .sbfd = ss->parent,
334 .count = 0,
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)
348 asymbol **csymp;
349 asymbol **ret = NULL;
350 for (csymp = sbfd->syms.data; csymp < sbfd->syms.data + sbfd->syms.size;
351 csymp++) {
352 asymbol *csymtemp = *csymp;
353 if (bfd_is_const_section(sym->section) && sym == csymtemp)
354 return csymp;
355 if ((csymtemp->flags & BSF_DEBUGGING) != 0 ||
356 sym->section != csymtemp->section ||
357 sym->value != csymtemp->value)
358 continue;
359 if ((csymtemp->flags & BSF_GLOBAL) != 0)
360 return csymp;
361 if (ret == NULL)
362 ret = csymp;
364 if (ret != NULL)
365 return ret;
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;
371 return ret;
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)
384 return NULL;
385 char *dot = strrchr(sym->name, '.');
386 if (dot == NULL || dot[1 + strspn(dot + 1, "0123546789")] != '\0')
387 return NULL;
388 char *basename = strndup(sym->name, dot - sym->name);
389 char *mangled_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);
394 else
395 assert(asprintf(&mangled_name, "%s<%s>", basename,
396 find_caller(ss, sym)) >= 0);
397 return mangled_name;
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);
406 char *label;
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);
413 } else {
414 asymbol *gsym = canonical_symbol(sbfd, sym);
416 if (gsym == NULL)
417 assert(asprintf(&label, "%s+%lx<%.*s>",
418 sym->section->name,
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);
428 else
429 assert(asprintf(&label, "%s<%.*s>",
430 gsym->name, flen, filename) >= 0);
433 return label;
436 static void init_label_map(struct superbfd *sbfd)
438 vec_init(&sbfd->maps);
439 struct label_map *map, *map2;
441 asymbol **symp;
442 for (symp = sbfd->syms.data;
443 symp < sbfd->syms.data + sbfd->syms.size; symp++) {
444 asymbol *csym = canonical_symbol(sbfd, *symp);
445 if (csym == NULL)
446 continue;
447 for (map = sbfd->maps.data;
448 map < sbfd->maps.data + sbfd->maps.size; map++) {
449 if (map->csym == csym)
450 break;
452 if (map < sbfd->maps.data + sbfd->maps.size)
453 continue;
454 map = vec_grow(&sbfd->maps, 1);
455 map->csym = csym;
456 map->count = 0;
457 map->index = 0;
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)
465 continue;
466 map->count++;
467 if (map2 < map)
468 map->index++;
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) {
476 char *buf;
477 assert(asprintf(&buf, "%s~%d", map->label,
478 map->index) >= 0);
479 map->label = buf;
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)
491 return map->label;
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)
502 continue;
503 printf(" %s -> %s\n", map->label, map->orig_label);
507 void label_map_set(struct superbfd *sbfd, const char *oldlabel,
508 const char *label)
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)
516 DIE;
517 map->label = label;
518 return;
521 DIE;