Use kid instead of addstr_all in objmanip export mode.
[ksplice.git] / objmanip.c
blob5c35b50429e2632ae74eb9880f07c09f99d623fe
1 /* This file is based in part on objcopy.c from GNU Binutils v2.17.
3 * Copyright (C) 1991-2006 Free Software Foundation, Inc.
4 * Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 * 02110-1301, USA.
20 /* objmanip performs various object file manipulations for Ksplice. Its first
21 * argument is always an object file, which is modified in-place during
22 * objmanip's execution. (objmanip's code is similar to objcopy from GNU
23 * binutils because every manipulation that objmanip performs is essentially a
24 * "copy" operation with certain changes which make the new version different
25 * from the old version). objmanip has four modes of operation:
27 * (1) keep mode
29 * This mode is the first objmanip step in processing the target object files.
31 * This mode can be broken down into two submodes, called "keep-primary" (which
32 * is used to prepare the primary kernel module) and "keep-helper" (which is
33 * used to prepare the helper kernel module):
35 * (a) keep-primary: "objmanip file.o keep-primary ADDSTR sect_1 ... sect_n"
37 * In this submode, only certain sections are kept; all other sections are
38 * discarded. Specifically, the following sections are kept: the listed
39 * sections (sect_1 ... sect_n), certain sections referenced by the listed
40 * sections, and certain special sections. The sections that are kept have
41 * ADDSTR added to the end of their names.
43 * The sections that are kept have most of their ELF relocations removed.
44 * (Relocations that point to sections that are being kept are not removed; all
45 * other relocations are removed). Information about each of the removed ELF
46 * relocations is printed to STDOUT (ksplice-create will save this information
47 * into Ksplice-specific ELF sections for the primary kernel module to use
48 * later).
50 * Each line of the STDOUT output represents a single place within the ELF
51 * object file at which a relocation has been removed. Each line contains the
52 * following fields, separated by spaces: an ELF symbol name, the name of a
53 * section previously containing a relocation pointing to that symbol, the
54 * offset (within that section) of the former relocation to that symbol, a bit
55 * representing whether that ELF relocation is PC-relative, and the ELF addend
56 * value for that relocation.
58 * (b) keep-helper: "objmanip file.o keep-helper ADDSTR"
60 * In this submode, essentially all sections are kept and have ADDSTR added to
61 * the end of their names.
63 * The sections that are kept have all of their ELF relocations removed.
64 * Information about each of the removed ELF relocations is printed to STDOUT
65 * (ksplice-create will save this information into Ksplice-specific ELF
66 * sections for the helper kernel module to use later).
68 * The fields of the STDOUT output are the same as with keep-primary.
70 * (2) globalize mode: "objmanip file.o globalize GLOBALIZESTR"
72 * This mode is the second objmanip step in processing the target object files.
73 * In this mode, all symbols whose names end in GLOBALIZESTR will be
74 * duplicated, with the duplicate symbols differing slightly from the original
75 * symbols. The duplicate symbols will have the string "_global" added to the
76 * end of their symbol names, and they will be global ELF symbols, regardless
77 * of whether the corresponding original symbol was global.
79 * (3) sizelist mode: "objmanip file.o sizelist"
81 * After the target object files have been linked into a single collection
82 * object file, this mode is used in order to obtain a list of all of the
83 * functions in the collection object file. Each line of the STDOUT output
84 * contains an ELF section name and that section's size, as presented by BFD's
85 * bfd_print_symbol function.
87 * (4) rmsyms mode: "objmanip file.o rmsyms sym_1 ... sym_n"
89 * This mode is the final objmanip step in preparing the Ksplice kernel
90 * modules. In this mode, any ELF relocations involving the listed symbols
91 * (sym_1 ... sym_n) are removed, and information about each of the removed
92 * relocations is printed to STDOUT.
94 * The fields of the STDOUT output are the same as with keep-primary.
97 #define _GNU_SOURCE
98 #include "objcommon.h"
99 #include "kmodsrc/ksplice.h"
100 #include <stdint.h>
101 #include <stdarg.h>
102 #include <stdlib.h>
103 #include <stdio.h>
104 #include <limits.h>
106 DECLARE_VEC_TYPE(const char *, str_vec);
108 struct wsect {
109 asection *sect;
110 struct wsect *next;
113 struct specsect {
114 const char *sectname;
115 int entry_size;
118 struct export_desc {
119 const char *sectname;
120 struct str_vec names;
122 DECLARE_VEC_TYPE(struct export_desc, export_desc_vec);
124 void rm_some_relocs(struct supersect *ss);
125 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc);
126 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto);
127 void write_ksplice_size(struct superbfd *sbfd, asymbol **symp);
128 void write_ksplice_patch(struct superbfd *sbfd, const char *symname);
129 void rm_from_special(struct superbfd *sbfd, const struct specsect *s);
130 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored);
131 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
132 void *looking_for);
133 bfd_boolean copy_object(bfd *ibfd, bfd *obfd);
134 void setup_section(bfd *ibfd, asection *isection, void *obfdarg);
135 static void setup_new_section(bfd *obfd, struct supersect *ss);
136 static void write_section(bfd *obfd, asection *osection, void *arg);
137 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
138 void *ignored);
139 static void ss_mark_symbols_used_in_relocations(struct supersect *ss);
140 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
141 struct asymbolp_vec *isyms);
142 int match_varargs(const char *str);
143 void read_str_set(struct str_vec *strs);
144 int str_in_set(const char *str, const struct str_vec *strs);
145 int want_section(asection *sect);
146 const struct specsect *is_special(asection *sect);
147 struct supersect *make_section(struct superbfd *sbfd, const char *name);
148 void __attribute__((format(printf, 3, 4)))
149 write_string(struct supersect *ss, const char **addr, const char *fmt, ...);
150 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed);
151 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
152 const char *export_type, int del);
154 char **varargs;
155 int varargs_count;
156 struct str_vec sections, entrysyms, newgsyms, newsyms, delsyms;
157 struct export_desc_vec exports;
159 const char *modestr, *addstr_all = "", *kid;
161 struct wsect *wanted_sections = NULL;
163 const struct specsect special_sections[] = {
164 {".altinstructions", 2 * sizeof(void *) + 4},
165 {".smp_locks", sizeof(void *)},
166 {".parainstructions", sizeof(void *) + 4},
167 }, *const end_special_sections = *(&special_sections + 1);
169 #define mode(str) starts_with(modestr, str)
171 DECLARE_VEC_TYPE(unsigned long, addr_vec);
172 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
173 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
174 vec_init);
175 struct addr_vec_hash system_map;
177 void load_system_map()
179 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
180 assert(config_dir);
181 char *file;
182 assert(asprintf(&file, "%s/System.map", config_dir) >= 0);
183 FILE *fp = fopen(file, "r");
184 assert(fp);
185 addr_vec_hash_init(&system_map);
186 unsigned long addr;
187 char type;
188 char *sym;
189 while (fscanf(fp, "%lx %c %as\n", &addr, &type, &sym) == 3)
190 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
191 1) = addr;
192 fclose(fp);
195 int main(int argc, char *argv[])
197 char *debug_name;
198 assert(asprintf(&debug_name, "%s.pre%s", argv[1], argv[2]) >= 0);
199 rename(argv[1], debug_name);
201 bfd_init();
202 bfd *ibfd = bfd_openr(debug_name, NULL);
203 assert(ibfd);
205 char **matching;
206 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
208 const char *output_target = bfd_get_target(ibfd);
209 bfd *obfd = bfd_openw(argv[1], output_target);
210 assert(obfd);
212 struct superbfd *isbfd = fetch_superbfd(ibfd);
214 modestr = argv[2];
215 if (mode("keep") || mode("sizelist") || mode("patchlist")) {
216 addstr_all = argv[3];
217 } else if (mode("export")) {
218 kid = argv[3];
219 } else if (mode("rmsyms")) {
220 varargs = &argv[3];
221 varargs_count = argc - 3;
224 if (mode("export") || mode("keep") || mode("globalize-new") ||
225 mode("rmrelocs") || mode("sizelist") || mode("patchlist")) {
226 read_str_set(&sections);
227 read_str_set(&entrysyms);
228 read_str_set(&newgsyms);
229 read_str_set(&newsyms);
230 read_str_set(&delsyms);
231 vec_init(&exports);
232 /* https://bugzilla.redhat.com/show_bug.cgi?id=431832 */
233 while (ungetc(getc(stdin), stdin) != EOF) {
234 char *sectname;
235 int ret = scanf("%as", &sectname);
236 if (ret == EOF)
237 break;
238 assert(ret == 1);
239 struct export_desc *ed = vec_grow(&exports, 1);
240 ed->sectname = sectname;
241 read_str_set(&ed->names);
245 if (mode("keep") || mode("sizelist") || mode("rmsyms") ||
246 mode("rmrelocs"))
247 load_system_map();
249 if (mode("keep")) {
250 while (1) {
251 const struct wsect *tmp = wanted_sections;
252 bfd_map_over_sections(ibfd, mark_wanted_if_referenced,
253 NULL);
254 if (tmp == wanted_sections)
255 break;
259 asymbol **symp;
260 for (symp = isbfd->syms.data;
261 mode("sizelist") && symp < isbfd->syms.data + isbfd->syms.size;
262 symp++) {
263 asymbol *sym = *symp;
264 if ((sym->flags & BSF_FUNCTION)
265 && sym->value == 0 && !(sym->flags & BSF_WEAK))
266 write_ksplice_size(isbfd, symp);
267 if (starts_with(sym->section->name, ".rodata") &&
268 (sym->flags & BSF_DEBUGGING) == 0 &&
269 sym->value == 0 && (sym->flags & BSF_WEAK) == 0)
270 write_ksplice_size(isbfd, symp);
273 if (mode("patchlist")) {
274 const char **symname;
275 for (symname = entrysyms.data;
276 symname < entrysyms.data + entrysyms.size; symname++)
277 write_ksplice_patch(isbfd, *symname);
280 asection *p;
281 for (p = ibfd->sections; p != NULL; p = p->next) {
282 struct supersect *ss = fetch_supersect(isbfd, p);
283 if (is_special(p) || starts_with(p->name, ".ksplice"))
284 continue;
285 if (want_section(p) || mode("rmsyms"))
286 rm_some_relocs(ss);
289 const struct specsect *ss;
290 if (mode("keep")) {
291 for (ss = special_sections; ss != end_special_sections; ss++)
292 rm_from_special(isbfd, ss);
295 if (mode("export")) {
296 const struct export_desc *ed;
297 for (ed = exports.data; ed < exports.data + exports.size;
298 ed++) {
299 if (starts_with(ed->sectname, "del___ksymtab")) {
300 const char *export_type =
301 ed->sectname + strlen("del___ksymtab");
302 const char **symname;
303 for (symname = ed->names.data;
304 symname < ed->names.data + ed->names.size;
305 symname++)
306 write_ksplice_export(isbfd, *symname,
307 export_type, 1);
308 } else {
309 rm_some_exports(isbfd, ed);
314 copy_object(ibfd, obfd);
315 assert(bfd_close(obfd));
316 assert(bfd_close(ibfd));
317 return EXIT_SUCCESS;
320 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed)
322 assert(starts_with(ed->sectname, "__ksymtab"));
323 const char *export_type = ed->sectname + strlen("__ksymtab");
324 asection *sym_sect = bfd_get_section_by_name(isbfd->abfd, ed->sectname);
325 assert(sym_sect != NULL);
326 char *export_crc_name;
327 assert(asprintf(&export_crc_name, "__kcrctab%s", export_type) >= 0);
328 asection *crc_sect = bfd_get_section_by_name(isbfd->abfd,
329 export_crc_name);
330 struct supersect *ss, *crc_ss = NULL;
331 ss = fetch_supersect(isbfd, sym_sect);
332 if (crc_sect != NULL)
333 crc_ss = fetch_supersect(isbfd, crc_sect);
335 if (crc_ss != NULL)
336 assert(ss->contents.size * sizeof(unsigned long) ==
337 crc_ss->contents.size * sizeof(struct kernel_symbol));
339 struct supersect orig_ss, orig_crc_ss;
340 supersect_move(&orig_ss, ss);
341 if (crc_ss != NULL)
342 supersect_move(&orig_crc_ss, crc_ss);
344 struct kernel_symbol *orig_ksym;
345 unsigned long *orig_crc;
346 for (orig_ksym = orig_ss.contents.data,
347 orig_crc = orig_crc_ss.contents.data;
348 (void *)orig_ksym < orig_ss.contents.data + orig_ss.contents.size;
349 orig_ksym++, orig_crc++) {
350 asymbol *sym;
351 read_reloc(&orig_ss, &orig_ksym->value,
352 sizeof(orig_ksym->value), &sym);
353 if (!str_in_set(sym->name, &ed->names))
354 continue;
356 struct kernel_symbol *ksym = sect_grow(ss, 1, typeof(*ksym));
357 sect_copy(ss, &ksym->value, &orig_ss, &orig_ksym->value, 1);
358 /* Replace name with a mangled name */
359 write_ksplice_export(ss->parent, sym->name, export_type, 0);
360 write_string(ss, (const char **)&ksym->name,
361 "DISABLED_%s_%s", sym->name, kid);
363 if (crc_ss != NULL)
364 sect_copy(crc_ss,
365 sect_grow(crc_ss, 1, typeof(*orig_crc)),
366 &orig_crc_ss, orig_crc, 1);
370 void rm_some_relocs(struct supersect *ss)
372 struct arelentp_vec orig_relocs;
373 vec_move(&orig_relocs, &ss->relocs);
375 arelent **relocp;
376 for (relocp = orig_relocs.data;
377 relocp < orig_relocs.data + orig_relocs.size; relocp++) {
378 int rm_reloc = 0;
379 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
381 if (mode("rmsyms") && match_varargs(sym_ptr->name))
382 rm_reloc = 1;
384 if (mode("keep") || mode("rmrelocs"))
385 rm_reloc = 1;
387 if (mode("keep-primary") && want_section(sym_ptr->section))
388 rm_reloc = 0;
390 if (mode("rmrelocs") &&
391 (str_in_set(sym_ptr->name, &newsyms) ||
392 bfd_is_und_section(sym_ptr->section) ||
393 (sym_ptr->flags & BSF_FUNCTION) == 0))
394 rm_reloc = 0;
396 if (mode("finalize") && bfd_is_und_section(sym_ptr->section))
397 rm_reloc = 1;
399 if (rm_reloc)
400 write_ksplice_reloc(ss, *relocp);
401 else
402 *vec_grow(&ss->relocs, 1) = *relocp;
406 struct supersect *make_section(struct superbfd *sbfd, const char *name)
408 asection *sect = bfd_get_section_by_name(sbfd->abfd, name);
409 if (sect != NULL)
410 return fetch_supersect(sbfd, sect);
411 else
412 return new_supersect(sbfd, name);
415 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
416 bfd_vma offset)
418 bfd_reloc_code_real_type code;
419 switch (bfd_arch_bits_per_address(ss->parent->abfd)) {
420 case 32:
421 code = BFD_RELOC_32;
422 break;
423 case 64:
424 code = BFD_RELOC_64;
425 break;
426 default:
427 DIE;
430 arelent *reloc = malloc(sizeof(*reloc));
431 reloc->sym_ptr_ptr = symp;
432 reloc->address = addr - ss->contents.data;
433 reloc->howto = bfd_reloc_type_lookup(ss->parent->abfd, code);
434 reloc->addend = offset;
435 *vec_grow(&ss->new_relocs, 1) = reloc;
438 void write_string(struct supersect *ss, const char **addr, const char *fmt, ...)
440 va_list ap;
441 va_start(ap, fmt);
442 int len = vsnprintf(NULL, 0, fmt, ap);
443 va_end(ap);
444 struct supersect *str_ss = make_section(ss->parent, ".ksplice_str");
445 char *buf = sect_grow(str_ss, len + 1, char);
446 va_start(ap, fmt);
447 vsnprintf(buf, len + 1, fmt, ap);
448 va_end(ap);
450 write_reloc(ss, addr, &str_ss->symbol,
451 (void *)buf - str_ss->contents.data);
454 void write_system_map_array(struct superbfd *sbfd, struct supersect *ss,
455 const unsigned long **sym_addrs,
456 unsigned long *num_sym_addrs, asymbol *sym)
458 const char *system_map_name = sym->name;
459 const char **prefix;
460 for (prefix = (const char *[]){".text.", ".data.", ".bss.", NULL};
461 *prefix != NULL; prefix++) {
462 if (starts_with(system_map_name, *prefix))
463 system_map_name += strlen(*prefix);
465 struct addr_vec *addrs = addr_vec_hash_lookup(&system_map,
466 system_map_name, FALSE);
467 if (addrs != NULL) {
468 struct supersect *array_ss = make_section(sbfd,
469 ".ksplice_array");
470 void *buf = sect_grow(array_ss, addrs->size,
471 typeof(*addrs->data));
472 memcpy(buf, addrs->data, addrs->size * sizeof(*addrs->data));
473 *num_sym_addrs = addrs->size;
474 write_reloc(ss, sym_addrs, &array_ss->symbol,
475 buf - array_ss->contents.data);
476 } else {
477 *num_sym_addrs = 0;
478 *sym_addrs = NULL;
482 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc)
484 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
486 reloc_howto_type *howto = orig_reloc->howto;
488 bfd_vma addend = get_reloc_offset(ss, orig_reloc, 0);
489 blot_section(ss, orig_reloc->address, howto);
491 struct supersect *kreloc_ss = make_section(ss->parent,
492 mode("rmsyms") ?
493 ".ksplice_init_relocs" :
494 ".ksplice_relocs");
495 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
496 struct ksplice_reloc);
498 write_string(kreloc_ss, &kreloc->sym_name, "%s%s",
499 sym_ptr->name, addstr_all);
500 write_reloc(kreloc_ss, &kreloc->blank_addr,
501 &ss->symbol, orig_reloc->address);
502 kreloc->blank_offset = (unsigned long)orig_reloc->address;
503 write_system_map_array(ss->parent, kreloc_ss, &kreloc->sym_addrs,
504 &kreloc->num_sym_addrs, sym_ptr);
505 kreloc->pcrel = howto->pc_relative;
506 kreloc->addend = addend;
507 kreloc->size = bfd_get_reloc_size(howto);
508 kreloc->dst_mask = howto->dst_mask;
509 kreloc->rightshift = howto->rightshift;
512 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
514 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto)
516 int bits = bfd_get_reloc_size(howto) * 8;
517 void *address = ss->contents.data + offset;
518 bfd_vma x = bfd_get(bits, ss->parent->abfd, address);
519 x = (x & ~howto->dst_mask) |
520 ((bfd_vma)0x7777777777777777LL & howto->dst_mask);
521 bfd_put(bits, ss->parent->abfd, x, address);
524 void write_ksplice_size(struct superbfd *sbfd, asymbol **symp)
526 asymbol *sym = *symp;
528 /* We call bfd_print_symbol in order to get access to
529 * the size associated with the function symbol, which
530 * is not otherwise available through the BFD API
532 char *buf = NULL;
533 size_t bufsize = 0;
534 FILE *fp = open_memstream(&buf, &bufsize);
535 bfd_print_symbol(sbfd->abfd, fp, sym, bfd_print_symbol_all);
536 fclose(fp);
537 assert(buf != NULL);
539 unsigned long symsize;
540 char *symname;
541 int len;
542 assert(sscanf(buf, "%*[^\t]\t%lx %as%n", &symsize, &symname, &len) >=
544 assert(buf[len] == '\0');
545 assert(strcmp(symname, sym->name) == 0);
546 free(symname);
547 free(buf);
549 struct supersect *ksize_ss = make_section(sbfd, ".ksplice_sizes");
550 struct ksplice_size *ksize = sect_grow(ksize_ss, 1,
551 struct ksplice_size);
553 write_string(ksize_ss, &ksize->name, "%s%s%s", sym->name, addstr_all,
554 mode("sizelist-primary") ? "_post" : "_pre");
555 ksize->size = symsize;
556 ksize->flags = 0;
557 if (mode("sizelist-helper") &&
558 str_in_set(sym->name, &delsyms) && (sym->flags & BSF_FUNCTION))
559 ksize->flags |= KSPLICE_SIZE_DELETED;
560 if (starts_with(sym->section->name, ".rodata"))
561 ksize->flags |= KSPLICE_SIZE_RODATA;
562 write_reloc(ksize_ss, &ksize->thismod_addr, symp, 0);
563 write_system_map_array(sbfd, ksize_ss, &ksize->sym_addrs,
564 &ksize->num_sym_addrs, sym);
567 void write_ksplice_patch(struct superbfd *sbfd, const char *symname)
569 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
570 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
571 struct ksplice_patch);
573 asymbol **symp;
574 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
575 symp++) {
576 if (strcmp((*symp)->name, symname) == 0)
577 break;
579 assert(symp < sbfd->syms.data + sbfd->syms.size);
581 write_string(kpatch_ss, &kpatch->oldstr, "%s%s_pre",
582 symname, addstr_all);
583 kpatch->oldaddr = 0;
584 kpatch->saved = NULL;
585 kpatch->trampoline = NULL;
586 write_reloc(kpatch_ss, &kpatch->repladdr, symp, 0);
589 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
590 const char *export_type, int del)
592 struct supersect *export_ss = make_section(sbfd, ".ksplice_exports");
593 struct ksplice_export *export = sect_grow(export_ss, 1,
594 struct ksplice_export);
596 write_string(export_ss, &export->type, "%s", export_type);
597 if (del) {
598 write_string(export_ss, &export->name, "%s", symname);
599 write_string(export_ss, &export->new_name,
600 "DISABLED_%s_%s", symname, kid);
601 } else {
602 write_string(export_ss, &export->new_name, "%s", symname);
603 write_string(export_ss, &export->name, "DISABLED_%s_%s",
604 symname, kid);
608 void rm_from_special(struct superbfd *sbfd, const struct specsect *s)
610 asection *isection = bfd_get_section_by_name(sbfd->abfd, s->sectname);
611 if (isection == NULL)
612 return;
614 struct supersect *ss = fetch_supersect(sbfd, isection), orig_ss;
615 supersect_move(&orig_ss, ss);
617 const void *orig_entry;
618 for (orig_entry = orig_ss.contents.data;
619 orig_entry < orig_ss.contents.data + orig_ss.contents.size;
620 orig_entry += align(s->entry_size, 1 << ss->alignment)) {
621 asymbol *sym;
622 read_reloc(&orig_ss, orig_entry, sizeof(void *), &sym);
624 asection *p;
625 for (p = sbfd->abfd->sections; p != NULL; p = p->next) {
626 if (sym->section == p
627 && !is_special(p) && !want_section(p))
628 break;
630 if (p != NULL)
631 continue;
633 sect_copy(ss, sect_do_grow(ss, 1, s->entry_size,
634 1 << ss->alignment),
635 &orig_ss, orig_entry, s->entry_size);
639 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
641 if (want_section(sect))
642 return;
643 if (!starts_with(sect->name, ".text")
644 && !starts_with(sect->name, ".rodata"))
645 return;
647 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
650 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
651 void *looking_for)
653 if (!want_section(looking_at) || is_special(looking_at))
654 return;
656 struct superbfd *sbfd = fetch_superbfd(abfd);
657 struct supersect *ss = fetch_supersect(sbfd, looking_at);
658 arelent **relocp;
659 for (relocp = ss->relocs.data;
660 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
661 asymbol *sym = *(*relocp)->sym_ptr_ptr;
662 if (sym->section == (asection *)looking_for &&
663 (!starts_with(sym->section->name, ".text") ||
664 get_reloc_offset(ss, *relocp, 1) != 0)) {
665 struct wsect *w = malloc(sizeof(*w));
666 w->sect = looking_for;
667 w->next = wanted_sections;
668 wanted_sections = w;
669 break;
674 /* Modified function from GNU Binutils objcopy.c */
675 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
677 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
679 bfd_vma start = bfd_get_start_address(ibfd);
681 flagword flags = bfd_get_file_flags(ibfd);
682 flags &= bfd_applicable_file_flags(obfd);
684 assert(bfd_set_start_address(obfd, start)
685 && bfd_set_file_flags(obfd, flags));
687 enum bfd_architecture iarch = bfd_get_arch(ibfd);
688 unsigned int imach = bfd_get_mach(ibfd);
689 assert(bfd_set_arch_mach(obfd, iarch, imach));
690 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
692 /* BFD mandates that all output sections be created and sizes set before
693 any output is done. Thus, we traverse all sections multiple times. */
694 bfd_map_over_sections(ibfd, setup_section, obfd);
696 struct supersect *new_supersects = fetch_superbfd(ibfd)->new_supersects;
697 struct supersect *ss;
698 for (ss = new_supersects; ss != NULL; ss = ss->next)
699 setup_new_section(obfd, ss);
701 /* Mark symbols used in output relocations so that they
702 are kept, even if they are local labels or static symbols.
704 Note we iterate over the input sections examining their
705 relocations since the relocations for the output sections
706 haven't been set yet. mark_symbols_used_in_relocations will
707 ignore input sections which have no corresponding output
708 section. */
710 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, NULL);
711 for (ss = new_supersects; ss != NULL; ss = ss->next)
712 ss_mark_symbols_used_in_relocations(ss);
713 struct asymbolp_vec osyms;
714 vec_init(&osyms);
715 filter_symbols(ibfd, obfd, &osyms, &fetch_superbfd(ibfd)->syms);
717 bfd_set_symtab(obfd, osyms.data, osyms.size);
719 /* This has to happen after the symbol table has been set. */
720 bfd_map_over_sections(obfd, write_section, NULL);
722 /* Allow the BFD backend to copy any private data it understands
723 from the input BFD to the output BFD. This is done last to
724 permit the routine to look at the filtered symbol table, which is
725 important for the ECOFF code at least. */
726 assert(bfd_copy_private_bfd_data(ibfd, obfd));
728 return TRUE;
731 /* Modified function from GNU Binutils objcopy.c */
732 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
734 bfd *obfd = obfdarg;
735 bfd_vma vma;
737 if (!want_section(isection))
738 return;
740 asection *osection = bfd_make_section_anyway(obfd, isection->name);
741 assert(osection != NULL);
743 struct superbfd *isbfd = fetch_superbfd(ibfd);
744 struct supersect *ss = fetch_supersect(isbfd, isection);
745 osection->userdata = ss;
746 bfd_set_section_flags(obfd, osection, ss->flags);
747 ss->symbol = osection->symbol;
748 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
750 vma = bfd_section_vma(ibfd, isection);
751 assert(bfd_set_section_vma(obfd, osection, vma));
753 osection->lma = isection->lma;
754 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
755 osection->entsize = isection->entsize;
756 osection->output_section = osection;
757 osection->output_offset = 0;
758 isection->output_section = osection;
759 isection->output_offset = 0;
760 return;
763 void setup_new_section(bfd *obfd, struct supersect *ss)
765 asection *osection = bfd_make_section_anyway(obfd, ss->name);
766 assert(osection != NULL);
767 bfd_set_section_flags(obfd, osection, ss->flags);
769 osection->userdata = ss;
770 ss->symbol = osection->symbol;
771 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
772 assert(bfd_set_section_vma(obfd, osection, 0));
774 osection->lma = 0;
775 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
776 osection->entsize = 0;
777 osection->output_section = osection;
778 osection->output_offset = 0;
781 void write_section(bfd *obfd, asection *osection, void *arg)
783 struct supersect *ss = osection->userdata;
785 if ((ss->flags & SEC_GROUP) != 0 || ss->contents.size == 0)
786 return;
788 arelent **relocp;
789 char *error_message;
790 for (relocp = ss->new_relocs.data;
791 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
792 bfd_put(bfd_get_reloc_size((*relocp)->howto) * 8, obfd, 0,
793 ss->contents.data + (*relocp)->address);
794 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
795 0, osection, &error_message) !=
796 bfd_reloc_ok) {
797 fprintf(stderr, "ksplice: error installing reloc: %s",
798 error_message);
799 DIE;
802 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
803 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
805 bfd_set_reloc(obfd, osection,
806 ss->relocs.size == 0 ? NULL : ss->relocs.data,
807 ss->relocs.size);
809 if (ss->flags & SEC_HAS_CONTENTS)
810 assert(bfd_set_section_contents
811 (obfd, osection, ss->contents.data, 0,
812 ss->contents.size));
815 /* Modified function from GNU Binutils objcopy.c
817 * Mark all the symbols which will be used in output relocations with
818 * the BSF_KEEP flag so that those symbols will not be stripped.
820 * Ignore relocations which will not appear in the output file.
822 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
823 void *ignored)
825 struct superbfd *sbfd = fetch_superbfd(abfd);
826 if (isection->output_section == NULL)
827 return;
829 struct supersect *ss = fetch_supersect(sbfd, isection);
830 ss_mark_symbols_used_in_relocations(ss);
833 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
835 /* Examine each symbol used in a relocation. If it's not one of the
836 special bfd section symbols, then mark it with BSF_KEEP. */
837 arelent **relocp;
838 for (relocp = ss->relocs.data;
839 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
840 asymbol *sym = *(*relocp)->sym_ptr_ptr;
841 if (!(bfd_is_const_section(sym->section) &&
842 sym == sym->section->symbol))
843 sym->flags |= BSF_KEEP;
847 /* Modified function from GNU Binutils objcopy.c
849 * Choose which symbol entries to copy.
850 * We don't copy in place, because that confuses the relocs.
851 * Return the number of symbols to print.
853 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
854 struct asymbolp_vec *isyms)
856 asymbol **symp;
857 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
858 asymbol *sym = *symp;
860 int keep;
862 if (mode("keep") && (sym->flags & BSF_GLOBAL) != 0)
863 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
865 if (mode("globalize-new") && str_in_set(sym->name, &newgsyms))
866 sym->flags = (sym->flags & ~BSF_LOCAL) | BSF_GLOBAL;
868 if ((sym->flags & BSF_KEEP) != 0 /* Used in relocation. */
869 || ((sym->flags & BSF_SECTION_SYM) != 0
870 && ((*(sym->section)->symbol_ptr_ptr)->flags
871 & BSF_KEEP) != 0))
872 keep = 1;
873 else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
874 keep = 1;
875 else if (bfd_decode_symclass(sym) == 'I')
876 /* Global symbols in $idata sections need to be retained.
877 External users of the library containing the $idata
878 section may reference these symbols. */
879 keep = 1;
880 else if ((sym->flags & BSF_GLOBAL) != 0
881 || (sym->flags & BSF_WEAK) != 0
882 || bfd_is_com_section(sym->section))
883 keep = 1;
884 else if ((sym->flags & BSF_DEBUGGING) != 0)
885 keep = 1;
886 else
887 keep = !bfd_is_local_label(ibfd, sym);
889 if (!want_section(sym->section))
890 keep = 0;
892 if (mode("rmsyms") && match_varargs(sym->name))
893 keep = 0;
895 if (keep)
896 *vec_grow(osyms, 1) = sym;
900 int match_varargs(const char *str)
902 int i;
903 for (i = 0; i < varargs_count; i++) {
904 if (strcmp(str, varargs[i]) == 0)
905 return 1;
907 return 0;
910 void read_str_set(struct str_vec *strs)
912 char *buf = NULL;
913 size_t n = 0;
914 assert(getline(&buf, &n, stdin) >= 0);
915 vec_init(strs);
916 char *saveptr;
917 while (1) {
918 char *str = strtok_r(buf, " \n", &saveptr);
919 buf = NULL;
920 if (str == NULL)
921 break;
922 *vec_grow(strs, 1) = str;
926 int str_in_set(const char *str, const struct str_vec *strs)
928 const char **strp;
929 for (strp = strs->data; strp < strs->data + strs->size; strp++) {
930 if (strcmp(str, *strp) == 0)
931 return 1;
933 return 0;
936 int want_section(asection *sect)
938 static const char *static_want[] = {
939 ".altinstructions",
940 ".altinstr_replacement",
941 ".smp_locks",
942 ".parainstructions",
943 NULL
946 if (!mode("keep"))
947 return 1;
949 if (mode("keep-primary") && bfd_is_abs_section(sect))
950 return 1;
951 const struct wsect *w = wanted_sections;
952 for (; w != NULL; w = w->next) {
953 if (w->sect == sect)
954 return 1;
957 if (starts_with(sect->name, ".ksplice"))
958 return 1;
959 if (mode("keep-helper") && starts_with(sect->name, ".text"))
960 return 1;
961 if (mode("keep-primary") && starts_with(sect->name, "__ksymtab"))
962 return 1;
963 if (mode("keep-primary") && starts_with(sect->name, "__kcrctab"))
964 return 1;
965 if (mode("keep-primary") && str_in_set(sect->name, &sections))
966 return 1;
968 int i;
969 for (i = 0; static_want[i] != NULL; i++) {
970 if (strcmp(sect->name, static_want[i]) == 0)
971 return 1;
973 return 0;
976 const struct specsect *is_special(asection *sect)
978 const struct specsect *ss;
979 for (ss = special_sections; ss != end_special_sections; ss++) {
980 if (strcmp(ss->sectname, sect->name) == 0)
981 return ss;
983 return NULL;