Replace want_section with a flag in the supersect.
[ksplice.git] / objcommon.c
blobea078ac0e61087c33de8d75f27bd77cf8d260d79
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 if (sect->userdata != NULL)
71 return sect->userdata;
73 struct supersect *new = malloc(sizeof(*new));
74 assert(new != NULL);
76 sect->userdata = new;
77 new->parent = sbfd;
78 new->name = sect->name;
79 new->flags = bfd_get_section_flags(sbfd->abfd, sect);
80 new->match = NULL;
81 new->new = false;
82 new->patch = false;
83 new->keep = true;
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,
95 sbfd->syms.data));
96 assert(new->relocs.size >= 0);
97 vec_init(&new->new_relocs);
99 vec_init(&new->syms);
100 asymbol **symp;
101 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
102 symp++) {
103 asymbol *sym = *symp;
104 if (sym->section == sect)
105 *vec_grow(&new->syms, 1) = sym;
108 return new;
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)
116 return ss;
119 struct supersect *new = malloc(sizeof(*new));
120 new->parent = sbfd;
121 new->name = name;
122 new->next = sbfd->new_supersects;
123 sbfd->new_supersects = new;
124 new->flags = SEC_ALLOC | SEC_HAS_CONTENTS | SEC_RELOC;
125 new->new = false;
126 new->patch = false;
127 new->keep = true;
129 vec_init(&new->contents);
130 new->alignment = 0;
131 vec_init(&new->relocs);
132 vec_init(&new->new_relocs);
134 return new;
137 void supersect_move(struct supersect *dest_ss, struct supersect *src_ss)
139 *dest_ss = *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);
153 return out + pad;
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,
159 bfd_size_type mod)
161 arelent **relocp;
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);
167 *reloc = **relocp;
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,
177 bfd_size_type mod)
179 asymbol **symp;
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) {
186 sym->value += mod;
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:
223 x |= -(x & signbit);
224 break;
225 case complain_overflow_unsigned:
226 break;
227 default:
228 DIE;
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;
236 if (adjust_pc)
237 add += size;
239 return x + add;
242 bfd_vma read_reloc(struct supersect *ss, const void *addr, size_t size,
243 asymbol **symp)
245 arelent **relocp;
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) {
252 if (symp != NULL)
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);
262 if (symp != NULL)
263 *symp = *bfd_abs_section_ptr->symbol_ptr_ptr;
264 return val;
267 char *str_pointer(struct supersect *ss, void *const *addr)
269 asymbol *sym;
270 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
271 char *str;
272 assert(asprintf(&str, "%s+%lx", sym->name, (unsigned long)offset) >= 0);
273 return str;
276 const void *read_pointer(struct supersect *ss, void *const *addr,
277 struct supersect **data_ssp)
279 asymbol *sym;
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)
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", data_ss->name,
287 (unsigned long)addr_offset(data_ss, addr));
288 return NULL;
290 if (data_ssp != NULL)
291 *data_ssp = data_ss;
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;
302 asymbol *sym;
303 asection *calling_section;
304 int count;
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);
312 arelent **relocp;
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)
321 search->count++;
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 = {
331 .sym = sym,
332 .sbfd = ss->parent,
333 .count = 0,
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)
347 asymbol **csymp;
348 asymbol **ret = NULL;
349 for (csymp = sbfd->syms.data; csymp < sbfd->syms.data + sbfd->syms.size;
350 csymp++) {
351 asymbol *csymtemp = *csymp;
352 if (bfd_is_const_section(sym->section) && sym == csymtemp)
353 return csymp;
354 if ((csymtemp->flags & BSF_DEBUGGING) != 0 ||
355 sym->section != csymtemp->section ||
356 sym->value != csymtemp->value)
357 continue;
358 if ((csymtemp->flags & BSF_GLOBAL) != 0)
359 return csymp;
360 if (ret == NULL)
361 ret = csymp;
363 if (ret != NULL)
364 return ret;
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;
370 return ret;
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)
383 return NULL;
384 char *dot = strrchr(sym->name, '.');
385 if (dot == NULL || dot[1 + strspn(dot + 1, "0123546789")] != '\0')
386 return NULL;
387 char *basename = strndup(sym->name, dot - sym->name);
388 char *mangled_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);
393 else
394 assert(asprintf(&mangled_name, "%s<%s>", basename,
395 find_caller(ss, sym)) >= 0);
396 return mangled_name;
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);
405 char *label;
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);
412 } else {
413 asymbol *gsym = canonical_symbol(sbfd, sym);
415 if (gsym == NULL)
416 assert(asprintf(&label, "%s+%lx<%.*s>",
417 sym->section->name,
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);
427 else
428 assert(asprintf(&label, "%s<%.*s>",
429 gsym->name, flen, filename) >= 0);
432 return label;
435 static void init_label_map(struct superbfd *sbfd)
437 vec_init(&sbfd->maps);
438 struct label_map *map, *map2;
440 asymbol **symp;
441 for (symp = sbfd->syms.data;
442 symp < sbfd->syms.data + sbfd->syms.size; symp++) {
443 asymbol *csym = canonical_symbol(sbfd, *symp);
444 if (csym == NULL)
445 continue;
446 for (map = sbfd->maps.data;
447 map < sbfd->maps.data + sbfd->maps.size; map++) {
448 if (map->csym == csym)
449 break;
451 if (map < sbfd->maps.data + sbfd->maps.size)
452 continue;
453 map = vec_grow(&sbfd->maps, 1);
454 map->csym = csym;
455 map->count = 0;
456 map->index = 0;
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)
464 continue;
465 map->count++;
466 if (map2 < map)
467 map->index++;
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) {
475 char *buf;
476 assert(asprintf(&buf, "%s~%d", map->label,
477 map->index) >= 0);
478 map->label = buf;
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)
490 return map->label;
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)
501 continue;
502 printf(" %s -> %s\n", map->label, map->orig_label);
506 void label_map_set(struct superbfd *sbfd, const char *oldlabel,
507 const char *label)
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)
515 DIE;
516 map->label = label;
517 return;
520 DIE;