Check for all required perl modules.
[ksplice.git] / objcommon.c
blobf2c3bcc5fc3b99ec309a5c9a47e3746b9b273f89
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 new->type = SS_TYPE_KSPLICE;
136 return new;
139 void supersect_move(struct supersect *dest_ss, struct supersect *src_ss)
141 *dest_ss = *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);
155 return out + pad;
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,
161 bfd_size_type mod)
163 arelent **relocp;
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);
169 *reloc = **relocp;
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,
179 bfd_size_type mod)
181 asymbol **symp;
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) {
188 sym->value += mod;
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:
225 x |= -(x & signbit);
226 break;
227 case complain_overflow_unsigned:
228 break;
229 default:
230 DIE;
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;
238 if (adjust_pc)
239 add += size;
241 return x + add;
244 bfd_vma read_reloc(struct supersect *ss, const void *addr, size_t size,
245 asymbol **symp)
247 arelent **relocp;
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) {
254 if (symp != NULL)
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);
264 if (symp != NULL)
265 *symp = *bfd_abs_section_ptr->symbol_ptr_ptr;
266 return val;
269 char *str_pointer(struct supersect *ss, void *const *addr)
271 asymbol *sym;
272 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
273 char *str;
274 assert(asprintf(&str, "%s+%lx", sym->name, (unsigned long)offset) >= 0);
275 return str;
278 const void *read_pointer(struct supersect *ss, void *const *addr,
279 struct supersect **data_ssp)
281 asymbol *sym;
282 bfd_vma offset = read_reloc(ss, addr, sizeof(*addr), &sym);
283 if (bfd_is_abs_section(sym->section) && sym->value + offset == 0)
284 return NULL;
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));
289 return NULL;
291 struct supersect *data_ss = fetch_supersect(ss->parent, sym->section);
292 if (data_ssp != NULL)
293 *data_ssp = data_ss;
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;
304 asymbol *sym;
305 asection *calling_section;
306 int count;
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);
314 arelent **relocp;
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)
323 search->count++;
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 = {
333 .sym = sym,
334 .sbfd = ss->parent,
335 .count = 0,
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)
349 asymbol **csymp;
350 asymbol **ret = NULL;
351 for (csymp = sbfd->syms.data; csymp < sbfd->syms.data + sbfd->syms.size;
352 csymp++) {
353 asymbol *csymtemp = *csymp;
354 if (bfd_is_const_section(sym->section) && sym == csymtemp)
355 return csymp;
356 if ((csymtemp->flags & BSF_DEBUGGING) != 0 ||
357 sym->section != csymtemp->section ||
358 sym->value != csymtemp->value)
359 continue;
360 if ((csymtemp->flags & BSF_GLOBAL) != 0)
361 return csymp;
362 if (ret == NULL)
363 ret = csymp;
365 if (ret != NULL)
366 return ret;
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;
372 return ret;
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)
385 return NULL;
386 char *dot = strrchr(sym->name, '.');
387 if (dot == NULL || dot[1 + strspn(dot + 1, "0123546789")] != '\0')
388 return NULL;
389 char *basename = strndup(sym->name, dot - sym->name);
390 char *mangled_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);
395 else
396 assert(asprintf(&mangled_name, "%s<%s>", basename,
397 find_caller(ss, sym)) >= 0);
398 return mangled_name;
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);
407 char *label;
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);
414 } else {
415 asymbol *gsym = canonical_symbol(sbfd, sym);
417 if (gsym == NULL)
418 assert(asprintf(&label, "%s+%lx<%.*s>",
419 sym->section->name,
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);
429 else
430 assert(asprintf(&label, "%s<%.*s>",
431 gsym->name, flen, filename) >= 0);
434 return label;
437 static void init_label_map(struct superbfd *sbfd)
439 vec_init(&sbfd->maps);
440 struct label_map *map, *map2;
442 asymbol **symp;
443 for (symp = sbfd->syms.data;
444 symp < sbfd->syms.data + sbfd->syms.size; symp++) {
445 asymbol *csym = canonical_symbol(sbfd, *symp);
446 if (csym == NULL)
447 continue;
448 for (map = sbfd->maps.data;
449 map < sbfd->maps.data + sbfd->maps.size; map++) {
450 if (map->csym == csym)
451 break;
453 if (map < sbfd->maps.data + sbfd->maps.size)
454 continue;
455 map = vec_grow(&sbfd->maps, 1);
456 map->csym = csym;
457 map->count = 0;
458 map->index = 0;
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)
466 continue;
467 map->count++;
468 if (map2 < map)
469 map->index++;
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) {
477 char *buf;
478 assert(asprintf(&buf, "%s~%d", map->label,
479 map->index) >= 0);
480 map->label = buf;
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)
492 return map->label;
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)
503 continue;
504 printf(" %s -> %s\n", map->label, map->orig_label);
508 void label_map_set(struct superbfd *sbfd, const char *oldlabel,
509 const char *label)
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)
517 DIE;
518 map->label = label;
519 return;
522 DIE;