Die when fetch_supersect is called on const sections.
[ksplice.git] / objmanip.c
blob7976a784786efb9cb76899bc9f1cdb6b1a9c54b5
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) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
5 * Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
6 * Tim Abbott <tabbott@mit.edu>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License, version 2.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 * 02110-1301, USA.
22 /* objmanip performs various object file manipulations for Ksplice. Its first
23 * two arguments are always an input object file and an output object file.
25 * - keep-primary: "objmanip <post.o> <out.o> keep-primary <pre.o> <kid>"
27 * This mode prepares the object file to be installed as a ksplice update. The
28 * kid argument is the ksplice id string for the ksplice update being built.
30 * - keep-helper: "objmanip <pre.o> <out.o> keep-helper"
32 * This mode prepares the object file to be used for run-pre matching. This
33 * involves replacing all ELF relocations with ksplice relocations and
34 * writing ksplice_section structures for each ELF text or data section.
36 * - rmsyms mode: "objmanip <in.o> <out.o> rmsyms
38 * In this mode, any ELF relocations involving the list of symbol names given on
39 * standard input are replaced with ksplice relocations. This is used only
40 * for KSPLICE_STANDALONE.
42 * - finalize mode: "objmanip <in.o> <out.o> finalize"
44 * In this mode, any ELF relocations to undefined symbols are replaced with
45 * ksplice relocations.
48 /* Always define KSPLICE_STANDALONE, even if you're using integrated Ksplice.
49 objmanip won't compile without it. */
50 #define KSPLICE_STANDALONE
52 #define _GNU_SOURCE
53 #include "objcommon.h"
54 #include "kmodsrc/ksplice.h"
55 #include "kmodsrc/offsets.h"
56 #include <stdint.h>
57 #include <stdarg.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <limits.h>
62 #define symbol_init(sym) *(sym) = (asymbol *)NULL
63 DEFINE_HASH_TYPE(asymbol *, symbol_hash, symbol_hash_init, symbol_hash_free,
64 symbol_hash_lookup, symbol_init);
66 struct export {
67 const char *name;
68 asection *sect;
70 DECLARE_VEC_TYPE(struct export, export_vec);
72 DECLARE_VEC_TYPE(const char *, str_vec);
74 struct wsect {
75 asection *sect;
76 struct wsect *next;
79 struct export_desc {
80 const char *sectname;
81 struct str_vec names;
83 DECLARE_VEC_TYPE(struct export_desc, export_desc_vec);
85 #define bool_init(b) *(b) = false
86 DEFINE_HASH_TYPE(bool, bool_hash, bool_hash_init, bool_hash_free,
87 bool_hash_lookup, bool_init);
89 #define ulong_init(x) *(x) = 0
90 DEFINE_HASH_TYPE(unsigned long, ulong_hash, ulong_hash_init,
91 ulong_hash_free, ulong_hash_lookup, ulong_init);
93 void do_keep_primary(struct superbfd *isbfd, const char *pre);
94 void do_keep_helper(struct superbfd *isbfd);
95 void do_finalize(struct superbfd *isbfd);
96 void do_rmsyms(struct superbfd *isbfd);
98 struct export_vec *get_export_syms(struct superbfd *sbfd);
99 void compare_exported_symbols(struct superbfd *oldsbfd,
100 struct superbfd *newsbfd, char *addstr);
101 bool relocs_equal(struct supersect *old_ss, struct supersect *new_ss);
102 static bool part_of_reloc(struct supersect *ss, unsigned long addr);
103 static bool nonrelocs_equal(struct supersect *old_ss, struct supersect *new_ss);
104 static void handle_section_symbol_renames(struct superbfd *oldsbfd,
105 struct superbfd *newsbfd);
107 void rm_relocs(struct superbfd *isbfd);
108 void rm_some_relocs(struct supersect *ss);
109 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc);
110 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto);
111 void write_ksplice_section(struct superbfd *sbfd, asymbol **symp);
112 void write_ksplice_patch(struct superbfd *sbfd, const char *sectname);
113 void write_ksplice_deleted_patch(struct superbfd *sbfd, const char *name,
114 const char *label);
115 void filter_table_sections(struct superbfd *isbfd);
116 void filter_table_section(struct superbfd *sbfd, const struct table_section *s);
117 void keep_if_referenced(bfd *abfd, asection *sect, void *ignored);
118 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
119 void *looking_for);
120 bfd_boolean copy_object(bfd *ibfd, bfd *obfd);
121 void setup_section(bfd *ibfd, asection *isection, void *obfdarg);
122 static void setup_new_section(bfd *obfd, struct supersect *ss);
123 static void write_section(bfd *obfd, asection *osection, void *arg);
124 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
125 void *ignored);
126 static void ss_mark_symbols_used_in_relocations(struct supersect *ss);
127 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
128 struct asymbolp_vec *isyms);
129 static bool deleted_table_section_symbol(bfd *abfd, asymbol *sym);
130 void read_str_set(struct str_vec *strs);
131 bool str_in_set(const char *str, const struct str_vec *strs);
132 bool is_table_section(asection *sect);
133 bool is_special(asection *sect);
134 struct supersect *make_section(struct superbfd *sbfd, const char *name);
135 void __attribute__((format(printf, 3, 4)))
136 write_string(struct supersect *ss, const char **addr, const char *fmt, ...);
137 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed);
138 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
139 const char *export_type, bool del);
140 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
141 bfd_vma offset);
142 arelent *create_reloc(struct supersect *ss, const void *addr, asymbol **symp,
143 bfd_vma offset);
144 static void match_global_symbol_sections(struct superbfd *oldsbfd,
145 struct superbfd *newsbfd);
146 static void match_sections_by_name(struct superbfd *oldsbfd,
147 struct superbfd *newsbfd);
148 static void match_sections_by_contents(struct superbfd *oldsbfd,
149 struct superbfd *newsbfd);
150 static void match_sections_by_label(struct superbfd *oldsbfd,
151 struct superbfd *newsbfd);
152 static void mark_new_sections(struct superbfd *sbfd);
153 static void handle_deleted_sections(struct superbfd *oldsbfd,
154 struct superbfd *newsbfd);
155 static void compare_matched_sections(struct superbfd *sbfd);
156 static void update_nonzero_offsets(struct superbfd *sbfd);
157 static void handle_nonzero_offset_relocs(struct supersect *ss);
159 struct str_vec delsects, rmsyms;
160 struct export_desc_vec exports;
161 bool changed;
163 const char *modestr, *kid;
165 struct superbfd *offsets_sbfd = NULL;
167 #define mode(str) starts_with(modestr, str)
169 DECLARE_VEC_TYPE(unsigned long, addr_vec);
170 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
171 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
172 vec_init);
173 struct addr_vec_hash system_map;
175 struct bool_hash system_map_written;
176 struct ulong_hash ksplice_symbol_offset;
177 struct ulong_hash ksplice_string_offset;
179 void load_system_map()
181 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
182 assert(config_dir);
183 char *file;
184 assert(asprintf(&file, "%s/System.map", config_dir) >= 0);
185 FILE *fp = fopen(file, "r");
186 assert(fp);
187 addr_vec_hash_init(&system_map);
188 unsigned long addr;
189 char type;
190 char *sym;
191 while (fscanf(fp, "%lx %c %as\n", &addr, &type, &sym) == 3)
192 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
193 1) = addr;
194 fclose(fp);
197 void load_offsets()
199 char *kmodsrc = getenv("KSPLICE_KMODSRC"), *offsets_file;
200 assert(kmodsrc != NULL);
201 assert(asprintf(&offsets_file, "%s/offsets.o", kmodsrc) >= 0);
202 bfd *offsets_bfd = bfd_openr(offsets_file, NULL);
203 assert(offsets_bfd != NULL);
204 char **matching;
205 assert(bfd_check_format_matches(offsets_bfd, bfd_object, &matching));
206 offsets_sbfd = fetch_superbfd(offsets_bfd);
209 bool matchable_data_section(struct superbfd *sbfd, asection *isection)
211 if (bfd_is_const_section(isection))
212 return false;
213 struct supersect *ss = fetch_supersect(sbfd, isection);
214 if (starts_with(isection->name, ".rodata")) {
215 if (starts_with(isection->name, ".rodata.str"))
216 return false;
217 return true;
219 if (starts_with(isection->name, ".data")) {
220 /* Ignore .data.percpu sections */
221 if (starts_with(isection->name, ".data.percpu"))
222 return false;
223 return ss->relocs.size != 0;
225 return false;
228 bool matchable_text_section(struct superbfd *sbfd, asection *isection)
230 if (bfd_is_const_section(isection))
231 return false;
232 if (starts_with(isection->name, ".text"))
233 return true;
234 if (starts_with(isection->name, ".exit.text")
235 && bfd_get_section_by_name(sbfd->abfd, ".exitcall.exit") == NULL)
236 return true;
237 return false;
240 bool ignored_section(struct superbfd *sbfd, asection *isection)
242 if (bfd_is_const_section(isection))
243 return false;
244 if (starts_with(isection->name, ".init"))
245 return true;
246 if (starts_with(isection->name, ".debug"))
247 return true;
248 return false;
251 bool unchangeable_section(struct superbfd *sbfd, asection *isection)
253 if (bfd_is_const_section(isection))
254 return false;
255 if (starts_with(isection->name, ".bss"))
256 return true;
257 if (starts_with(isection->name, ".data"))
258 return true;
259 return false;
262 int main(int argc, char *argv[])
264 bfd_init();
265 bfd *ibfd = bfd_openr(argv[1], NULL);
266 assert(ibfd);
268 char **matching;
269 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
271 const char *output_target = bfd_get_target(ibfd);
272 bfd *obfd = bfd_openw(argv[2], output_target);
273 assert(obfd);
275 struct superbfd *isbfd = fetch_superbfd(ibfd);
277 bool_hash_init(&system_map_written);
278 ulong_hash_init(&ksplice_symbol_offset);
279 ulong_hash_init(&ksplice_string_offset);
281 modestr = argv[3];
282 if (mode("keep-primary")) {
283 kid = argv[5];
284 do_keep_primary(isbfd, argv[4]);
285 } else if (mode("keep-helper")) {
286 do_keep_helper(isbfd);
287 } else if (mode("finalize")) {
288 do_finalize(isbfd);
289 } else if (mode("rmsyms")) {
290 do_rmsyms(isbfd);
293 copy_object(ibfd, obfd);
295 if (offsets_sbfd != NULL)
296 assert(bfd_close(offsets_sbfd->abfd));
297 assert(bfd_close(obfd));
298 assert(bfd_close(ibfd));
299 return EXIT_SUCCESS;
302 void do_keep_primary(struct superbfd *isbfd, const char *pre)
304 struct bfd *prebfd = bfd_openr(pre, NULL);
305 assert(prebfd != NULL);
306 char **matching;
307 assert(bfd_check_format_matches(prebfd, bfd_object, &matching));
309 struct superbfd *presbfd = fetch_superbfd(prebfd);
311 match_global_symbol_sections(presbfd, isbfd);
312 printf("Matched global\n");
313 match_sections_by_name(presbfd, isbfd);
314 printf("Matched by name\n");
315 match_sections_by_label(presbfd, isbfd);
316 printf("Matched by label\n");
317 match_sections_by_contents(presbfd, isbfd);
318 printf("Matched by contents\n");
320 do {
321 changed = false;
322 compare_matched_sections(isbfd);
323 update_nonzero_offsets(isbfd);
324 mark_new_sections(isbfd);
325 } while (changed);
326 vec_init(&delsects);
328 handle_deleted_sections(presbfd, isbfd);
329 handle_section_symbol_renames(presbfd, isbfd);
331 vec_init(&exports);
332 compare_exported_symbols(presbfd, isbfd, "");
333 compare_exported_symbols(isbfd, presbfd, "del_");
335 assert(bfd_close(prebfd));
337 load_system_map();
338 load_offsets();
340 asection *sect;
341 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
342 struct supersect *ss = fetch_supersect(isbfd, sect);
343 ss->keep = false;
344 if (is_special(sect))
345 ss->keep = true;
346 if (ss->new || ss->patch)
347 ss->keep = true;
350 const char **sectname;
351 printf("Label name changes:\n");
352 print_label_map(isbfd);
354 printf("Changed text sections:\n");
355 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
356 struct supersect *ss = fetch_supersect(isbfd, sect);
357 if (ss->patch)
358 printf(" %s\n", sect->name);
361 printf("New sections:\n");
362 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
363 struct supersect *ss = fetch_supersect(isbfd, sect);
364 if (ss->new)
365 printf(" %s\n", sect->name);
367 if (delsects.size != 0) {
368 printf("Deleted section names:\n");
369 for (sectname = delsects.data;
370 sectname < delsects.data + delsects.size; sectname++)
371 printf(" %s\n", *sectname);
373 const struct export_desc *ed;
374 for (ed = exports.data; ed < exports.data + exports.size; ed++) {
375 const char **symname;
376 bool del = starts_with(ed->sectname, "del___ksymtab");
377 const char *export_type = ed->sectname + strlen("__ksymtab");
378 if (del)
379 export_type += strlen("_del");
380 for (symname = ed->names.data;
381 symname < ed->names.data + ed->names.size; symname++)
382 printf("Export %s(%s): %s\n",
383 del ? "deletion" : "addition",
384 export_type, *symname);
387 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
388 struct supersect *ss = fetch_supersect(isbfd, sect);
389 if (!ss->patch && !ss->new)
390 continue;
391 asymbol **symp = canonical_symbolp(isbfd, sect->symbol);
392 if (symp == NULL)
393 DIE;
394 write_ksplice_section(isbfd, symp);
395 if (ss->patch)
396 write_ksplice_patch(isbfd, sect->name);
399 for (ed = exports.data; ed < exports.data + exports.size; ed++) {
400 if (starts_with(ed->sectname, "del___ksymtab")) {
401 const char *export_type =
402 ed->sectname + strlen("del___ksymtab");
403 const char **symname;
404 for (symname = ed->names.data;
405 symname < ed->names.data + ed->names.size;
406 symname++)
407 write_ksplice_export(isbfd, *symname,
408 export_type, true);
409 } else {
410 rm_some_exports(isbfd, ed);
414 rm_relocs(isbfd);
415 filter_table_sections(isbfd);
418 void do_keep_helper(struct superbfd *isbfd)
420 load_system_map();
421 load_offsets();
423 asection *sect;
424 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
425 struct supersect *ss = fetch_supersect(isbfd, sect);
426 ss->keep = false;
427 if (is_special(sect) && !starts_with(sect->name, "__ksymtab") &&
428 !starts_with(sect->name, "__kcrctab"))
429 ss->keep = true;
430 if (matchable_text_section(isbfd, sect))
431 ss->keep = true;
433 do {
434 changed = false;
435 bfd_map_over_sections(isbfd->abfd, keep_if_referenced, NULL);
436 } while (changed);
438 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
439 struct supersect *ss = fetch_supersect(isbfd, sect);
440 asymbol **symp = canonical_symbolp(isbfd, sect->symbol);
441 if (symp == NULL)
442 continue;
443 asymbol *sym = *symp;
444 if ((sym->flags & BSF_WEAK) != 0)
445 continue;
446 if (bfd_get_section_size(sect) == 0)
447 continue;
448 if (ss->keep && (matchable_text_section(isbfd, sect) ||
449 matchable_data_section(isbfd, sect)))
450 write_ksplice_section(isbfd, symp);
453 rm_relocs(isbfd);
454 filter_table_sections(isbfd);
457 void do_finalize(struct superbfd *isbfd)
459 load_system_map();
460 load_offsets();
461 rm_relocs(isbfd);
464 void do_rmsyms(struct superbfd *isbfd)
466 read_str_set(&rmsyms);
467 load_system_map();
468 rm_relocs(isbfd);
471 struct export_vec *get_export_syms(struct superbfd *sbfd)
473 asection *sect;
474 struct export_vec *exports;
475 exports = malloc(sizeof(*exports));
476 assert(exports != NULL);
477 vec_init(exports);
479 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
480 if (!starts_with(sect->name, "__ksymtab") ||
481 ends_with(sect->name, "_strings"))
482 continue;
483 struct supersect *ss = fetch_supersect(sbfd, sect);
484 struct kernel_symbol *sym;
485 assert(ss->contents.size * 2 == ss->relocs.size *
486 sizeof(struct kernel_symbol));
487 for (sym = ss->contents.data;
488 (void *)sym < ss->contents.data + ss->contents.size;
489 sym++) {
490 struct export *exp = vec_grow(exports, 1);
491 exp->name =
492 read_string(ss, (const char *const *)&sym->name);
493 exp->sect = sect;
496 return exports;
499 void compare_exported_symbols(struct superbfd *oldsbfd,
500 struct superbfd *newsbfd, char *addstr)
502 struct export_vec *new_exports, *old_exports;
503 new_exports = get_export_syms(newsbfd);
504 if (new_exports == NULL)
505 return;
506 old_exports = get_export_syms(oldsbfd);
507 struct export *old, *new;
508 asection *last_sect = NULL;
509 struct export_desc *ed;
510 for (new = new_exports->data; new < new_exports->data +
511 new_exports->size; new++) {
512 bool found = false;
513 if (old_exports != NULL) {
514 for (old = old_exports->data; old < old_exports->data +
515 old_exports->size; old++) {
516 if (strcmp(new->name, old->name) == 0 &&
517 strcmp(new->sect->name, old->sect->name)
518 == 0) {
519 found = true;
520 break;
524 if (last_sect != new->sect) {
525 last_sect = new->sect;
526 ed = vec_grow(&exports, 1);
527 char *sectname;
528 assert(asprintf(&sectname, "%s%s", addstr,
529 new->sect->name) >= 0);
530 ed->sectname = sectname;
531 vec_init(&ed->names);
533 if (!found)
534 *vec_grow(&ed->names, 1) = new->name;
538 void match_sections(struct supersect *oldss, struct supersect *newss)
540 if (oldss->match == newss && newss->match == oldss)
541 return;
542 if (oldss->match != NULL) {
543 fprintf(stderr, "Matching conflict: old %s: %s != %s\n",
544 oldss->name, oldss->match->name, newss->name);
545 DIE;
547 if (newss->match != NULL) {
548 fprintf(stderr, "Matching conflict: new %s: %s != %s\n",
549 newss->name, newss->match->name, oldss->name);
550 DIE;
552 oldss->match = newss;
553 newss->match = oldss;
554 printf("Matched old %s to new %s\n", oldss->name, newss->name);
557 static void match_global_symbol_sections(struct superbfd *oldsbfd,
558 struct superbfd *newsbfd)
560 asymbol **oldsymp, **newsymp;
561 for (oldsymp = oldsbfd->syms.data;
562 oldsymp < oldsbfd->syms.data + oldsbfd->syms.size; oldsymp++) {
563 asymbol *oldsym = *oldsymp;
564 if ((oldsym->flags & BSF_GLOBAL) == 0 ||
565 bfd_is_const_section(oldsym->section))
566 continue;
567 for (newsymp = newsbfd->syms.data;
568 newsymp < newsbfd->syms.data + newsbfd->syms.size;
569 newsymp++) {
570 asymbol *newsym = *newsymp;
571 if ((newsym->flags & BSF_GLOBAL) == 0 ||
572 bfd_is_const_section(oldsym->section))
573 continue;
574 if (strcmp(oldsym->name, newsym->name) != 0)
575 continue;
576 struct supersect *oldss =
577 fetch_supersect(oldsbfd, oldsym->section);
578 struct supersect *newss =
579 fetch_supersect(newsbfd, newsym->section);
580 match_sections(oldss, newss);
585 static void match_sections_by_name(struct superbfd *oldsbfd,
586 struct superbfd *newsbfd)
588 asection *newp, *oldp;
589 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
590 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
591 if (oldp == NULL || is_special(newp))
592 continue;
593 if (static_local_symbol(newsbfd,
594 canonical_symbol(newsbfd,
595 newp->symbol)))
596 continue;
598 struct supersect *oldss = fetch_supersect(oldsbfd, oldp);
599 struct supersect *newss = fetch_supersect(newsbfd, newp);
600 match_sections(oldss, newss);
604 static void match_sections_by_label(struct superbfd *oldsbfd,
605 struct superbfd *newsbfd)
607 asection *oldsect, *newsect;
608 struct supersect *oldss, *newss;
609 for (newsect = newsbfd->abfd->sections; newsect != NULL;
610 newsect = newsect->next) {
611 if (is_special(newsect))
612 continue;
613 for (oldsect = oldsbfd->abfd->sections; oldsect != NULL;
614 oldsect = oldsect->next) {
615 if (strcmp(label_lookup(newsbfd, newsect->symbol),
616 label_lookup(oldsbfd, oldsect->symbol)) != 0)
617 continue;
618 oldss = fetch_supersect(oldsbfd, oldsect);
619 newss = fetch_supersect(newsbfd, newsect);
620 match_sections(oldss, newss);
625 static void match_sections_by_contents(struct superbfd *oldsbfd,
626 struct superbfd *newsbfd)
628 asection *oldsect, *newsect;
629 struct supersect *oldss, *newss;
630 for (newsect = newsbfd->abfd->sections; newsect != NULL;
631 newsect = newsect->next) {
632 for (oldsect = oldsbfd->abfd->sections; oldsect != NULL;
633 oldsect = oldsect->next) {
634 oldss = fetch_supersect(oldsbfd, oldsect);
635 newss = fetch_supersect(newsbfd, newsect);
636 if (!matchable_data_section(newsbfd, newsect) ||
637 !matchable_data_section(oldsbfd, oldsect))
638 continue;
639 if (oldss->relocs.size != 0 || newss->relocs.size != 0)
640 continue;
641 if (oldss->contents.size != newss->contents.size)
642 continue;
643 if (memcmp(oldss->contents.data, newss->contents.data,
644 oldss->contents.size) != 0)
645 continue;
646 match_sections(oldss, newss);
651 static void mark_new_sections(struct superbfd *sbfd)
653 asection *sect;
654 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
655 if (is_special(sect) || ignored_section(sbfd, sect))
656 continue;
657 struct supersect *ss = fetch_supersect(sbfd, sect);
658 if (ss->match == NULL)
659 ss->new = true;
663 static void handle_deleted_sections(struct superbfd *oldsbfd,
664 struct superbfd *newsbfd)
666 asection *sect;
667 for (sect = oldsbfd->abfd->sections; sect != NULL; sect = sect->next) {
668 if (is_special(sect) || ignored_section(oldsbfd, sect))
669 continue;
670 if (!matchable_text_section(oldsbfd, sect))
671 continue;
672 struct supersect *ss = fetch_supersect(oldsbfd, sect);
673 if (ss->match != NULL)
674 continue;
675 const char *label = label_lookup(oldsbfd, sect->symbol);
676 *vec_grow(&delsects, 1) = label;
677 asymbol *csym = canonical_symbol(oldsbfd, sect->symbol);
678 write_ksplice_deleted_patch(newsbfd, csym->name, label);
682 static void handle_nonzero_offset_relocs(struct supersect *ss)
684 int i;
685 for (i = 0; i < ss->relocs.size; i++) {
686 asymbol *sym = *ss->relocs.data[i]->sym_ptr_ptr;
687 bfd_vma offset = get_reloc_offset(ss, ss->relocs.data[i], true);
688 if (sym->value + offset == 0)
689 continue;
690 if (!matchable_text_section(ss->parent, sym->section))
691 continue;
692 struct supersect *sym_ss = fetch_supersect(ss->parent,
693 sym->section);
694 if (!sym_ss->patch) {
695 changed = true;
696 printf("Changing %s because a relocation from sect %s "
697 "has a nonzero offset %lx+%lx into it\n",
698 sym_ss->name, ss->name,
699 (unsigned long)sym->value,
700 (unsigned long)offset);
702 sym_ss->patch = true;
706 static void update_nonzero_offsets(struct superbfd *sbfd)
708 asection *sect;
709 struct supersect *ss;
711 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
712 ss = fetch_supersect(sbfd, sect);
713 if (ss->new || ss->patch)
714 handle_nonzero_offset_relocs(ss);
718 static void compare_matched_sections(struct superbfd *newsbfd)
720 asection *newp;
721 struct supersect *old_ss, *new_ss;
722 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
723 new_ss = fetch_supersect(newsbfd, newp);
724 if (new_ss->match == NULL)
725 continue;
726 old_ss = new_ss->match;
728 if (nonrelocs_equal(old_ss, new_ss) &&
729 relocs_equal(old_ss, new_ss))
730 continue;
731 if (matchable_text_section(newsbfd, newp)) {
732 if (new_ss->patch)
733 continue;
734 new_ss->patch = true;
735 printf("Changing %s due to ", new_ss->name);
736 } else {
737 printf("Unmatching %s and %s due to ", old_ss->name,
738 new_ss->name);
739 new_ss->match = NULL;
740 old_ss->match = NULL;
742 if (new_ss->contents.size != old_ss->contents.size)
743 printf("differing sizes\n");
744 else if (memcmp(new_ss->contents.data, old_ss->contents.data,
745 new_ss->contents.size) != 0)
746 printf("differing contents\n");
747 else
748 printf("differing relocations\n");
749 changed = true;
750 if (unchangeable_section(newsbfd, newp))
751 DIE;
755 static void handle_section_symbol_renames(struct superbfd *oldsbfd,
756 struct superbfd *newsbfd)
758 asection *newp, *oldp;
759 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
760 struct supersect *newss = fetch_supersect(newsbfd, newp);
761 if (newss->match == NULL)
762 continue;
763 oldp = bfd_get_section_by_name(oldsbfd->abfd,
764 newss->match->name);
765 if (oldp == NULL)
766 continue;
768 const char *old_label = label_lookup(oldsbfd, oldp->symbol);
769 const char *new_label = label_lookup(newsbfd, newp->symbol);
771 if (strcmp(old_label, new_label) == 0)
772 continue;
773 label_map_set(newsbfd, new_label, old_label);
777 static bool part_of_reloc(struct supersect *ss, unsigned long addr)
779 arelent **relocp;
780 for (relocp = ss->relocs.data;
781 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
782 arelent *reloc = *relocp;
783 if (addr >= reloc->address &&
784 addr < reloc->address + reloc->howto->size)
785 return true;
787 return false;
790 static bool nonrelocs_equal(struct supersect *old_ss, struct supersect *new_ss)
792 int i;
793 if (old_ss->contents.size != new_ss->contents.size)
794 return false;
795 const unsigned char *old = old_ss->contents.data;
796 const unsigned char *new = new_ss->contents.data;
797 for (i = 0; i < old_ss->contents.size; i++) {
798 if (old[i] != new[i] &&
799 !(part_of_reloc(old_ss, i) && part_of_reloc(new_ss, i)))
800 return false;
802 return true;
806 * relocs_equal checks to see whether the old section and the new section
807 * reference different read-only data in their relocations -- if a hard-coded
808 * string has been changed between the old file and the new file, relocs_equal
809 * will detect the difference.
811 bool relocs_equal(struct supersect *old_ss, struct supersect *new_ss)
813 int i;
814 struct superbfd *oldsbfd = old_ss->parent;
815 struct superbfd *newsbfd = new_ss->parent;
817 if (old_ss->relocs.size != new_ss->relocs.size) {
818 printf("Different reloc count between %s and %s\n",
819 old_ss->name, new_ss->name);
820 return false;
823 for (i = 0; i < old_ss->relocs.size; i++) {
824 struct supersect *ro_old_ss, *ro_new_ss;
826 asymbol *old_sym = *old_ss->relocs.data[i]->sym_ptr_ptr;
827 asymbol *new_sym = *new_ss->relocs.data[i]->sym_ptr_ptr;
829 bfd_vma old_offset =
830 get_reloc_offset(old_ss, old_ss->relocs.data[i], true);
831 bfd_vma new_offset =
832 get_reloc_offset(new_ss, new_ss->relocs.data[i], true);
834 if (bfd_is_und_section(old_sym->section) ||
835 bfd_is_und_section(new_sym->section)) {
836 if (!bfd_is_und_section(new_sym->section) &&
837 matchable_text_section(newsbfd, new_sym->section) &&
838 old_offset != 0)
839 return false;
841 if (!bfd_is_und_section(old_sym->section) &&
842 matchable_text_section(oldsbfd, old_sym->section) &&
843 new_offset != 0)
844 return false;
846 if (strcmp(old_sym->name, new_sym->name) == 0 &&
847 old_offset == new_offset)
848 continue;
849 return false;
852 if (bfd_is_const_section(old_sym->section) ||
853 bfd_is_const_section(new_sym->section))
854 DIE;
856 ro_old_ss = fetch_supersect(oldsbfd, old_sym->section);
857 ro_new_ss = fetch_supersect(newsbfd, new_sym->section);
859 if (starts_with(ro_old_ss->name, ".rodata.str") &&
860 /* check it's not an out-of-range relocation to a string;
861 we'll just compare entire sections for them */
862 !(old_offset >= ro_old_ss->contents.size ||
863 new_offset >= ro_new_ss->contents.size)) {
864 if (strcmp(ro_old_ss->contents.data + old_sym->value +
865 old_offset,
866 ro_new_ss->contents.data + new_sym->value +
867 new_offset) != 0) {
868 printf("Strings differ between %s and %s\n",
869 old_ss->name, new_ss->name);
870 return false;
872 continue;
875 if (ro_old_ss->match != ro_new_ss ||
876 ro_new_ss->match != ro_old_ss) {
877 printf("Nonmatching relocs from %s to %s/%s\n",
878 new_ss->name, ro_new_ss->name, ro_old_ss->name);
879 return false;
882 if (old_sym->value + old_offset != new_sym->value + new_offset) {
883 printf("Offsets to %s/%s differ between %s and %s: "
884 "%lx+%lx/%lx+%lx\n", ro_old_ss->name,
885 ro_new_ss->name, old_ss->name, new_ss->name,
886 (unsigned long)old_sym->value,
887 (unsigned long)old_offset,
888 (unsigned long)new_sym->value,
889 (unsigned long)new_offset);
890 return false;
893 if ((old_sym->value + old_offset != 0 ||
894 new_sym->value + new_offset != 0) && ro_new_ss->patch) {
895 printf("Relocation from %s to nonzero offsets %lx+%lx/"
896 "%lx+%lx in changed section %s\n", new_ss->name,
897 (unsigned long)old_sym->value,
898 (unsigned long)old_offset,
899 (unsigned long)new_sym->value,
900 (unsigned long)new_offset,
901 new_sym->section->name);
902 return false;
906 return true;
909 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed)
911 assert(starts_with(ed->sectname, "__ksymtab"));
912 const char *export_type = ed->sectname + strlen("__ksymtab");
913 asection *sym_sect = bfd_get_section_by_name(isbfd->abfd, ed->sectname);
914 assert(sym_sect != NULL);
915 char *export_crc_name;
916 assert(asprintf(&export_crc_name, "__kcrctab%s", export_type) >= 0);
917 asection *crc_sect = bfd_get_section_by_name(isbfd->abfd,
918 export_crc_name);
919 struct supersect *ss, *crc_ss = NULL;
920 ss = fetch_supersect(isbfd, sym_sect);
921 if (crc_sect != NULL)
922 crc_ss = fetch_supersect(isbfd, crc_sect);
924 if (crc_ss != NULL)
925 assert(ss->contents.size * sizeof(unsigned long) ==
926 crc_ss->contents.size * sizeof(struct kernel_symbol));
928 struct supersect orig_ss, orig_crc_ss;
929 supersect_move(&orig_ss, ss);
930 if (crc_ss != NULL)
931 supersect_move(&orig_crc_ss, crc_ss);
933 struct kernel_symbol *orig_ksym;
934 unsigned long *orig_crc;
935 for (orig_ksym = orig_ss.contents.data,
936 orig_crc = orig_crc_ss.contents.data;
937 (void *)orig_ksym < orig_ss.contents.data + orig_ss.contents.size;
938 orig_ksym++, orig_crc++) {
939 asymbol *sym;
940 read_reloc(&orig_ss, &orig_ksym->value,
941 sizeof(orig_ksym->value), &sym);
942 if (!str_in_set(sym->name, &ed->names))
943 continue;
945 struct kernel_symbol *ksym = sect_grow(ss, 1, typeof(*ksym));
946 sect_copy(ss, &ksym->value, &orig_ss, &orig_ksym->value, 1);
947 /* Replace name with a mangled name */
948 write_ksplice_export(ss->parent, sym->name, export_type, false);
949 write_string(ss, (const char **)&ksym->name,
950 "DISABLED_%s_%s", sym->name, kid);
952 if (crc_ss != NULL)
953 sect_copy(crc_ss,
954 sect_grow(crc_ss, 1, typeof(*orig_crc)),
955 &orig_crc_ss, orig_crc, 1);
959 void rm_relocs(struct superbfd *isbfd)
961 asection *p;
962 for (p = isbfd->abfd->sections; p != NULL; p = p->next) {
963 struct supersect *ss = fetch_supersect(isbfd, p);
964 if (is_table_section(p) || starts_with(p->name, ".ksplice") ||
965 strcmp(p->name, ".fixup") == 0)
966 continue;
967 if (ss->keep || mode("rmsyms"))
968 rm_some_relocs(ss);
970 if (mode("finalize")) {
971 p = bfd_get_section_by_name(isbfd->abfd, ".ksplice_patches");
972 if (p != NULL) {
973 struct supersect *ss = fetch_supersect(isbfd, p);
974 rm_some_relocs(ss);
979 void rm_some_relocs(struct supersect *ss)
981 struct arelentp_vec orig_relocs;
982 vec_move(&orig_relocs, &ss->relocs);
984 arelent **relocp;
985 for (relocp = orig_relocs.data;
986 relocp < orig_relocs.data + orig_relocs.size; relocp++) {
987 bool rm_reloc = false;
988 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
990 if (mode("rmsyms") && str_in_set(sym_ptr->name, &rmsyms) &&
991 bfd_is_und_section(sym_ptr->section))
992 rm_reloc = true;
994 if (mode("keep"))
995 rm_reloc = true;
997 if (mode("keep-primary") &&
998 (bfd_is_const_section(sym_ptr->section) ||
999 fetch_supersect(ss->parent, sym_ptr->section)->new ||
1000 starts_with(sym_ptr->section->name, ".rodata.str")))
1001 rm_reloc = false;
1003 if (mode("finalize") && bfd_is_und_section(sym_ptr->section))
1004 rm_reloc = true;
1006 if (rm_reloc)
1007 write_ksplice_reloc(ss, *relocp);
1008 else
1009 *vec_grow(&ss->relocs, 1) = *relocp;
1013 struct supersect *make_section(struct superbfd *sbfd, const char *name)
1015 asection *sect = bfd_get_section_by_name(sbfd->abfd, name);
1016 if (sect != NULL)
1017 return fetch_supersect(sbfd, sect);
1018 else
1019 return new_supersect(sbfd, name);
1022 arelent *create_reloc(struct supersect *ss, const void *addr, asymbol **symp,
1023 bfd_vma offset)
1025 bfd_reloc_code_real_type code;
1026 switch (bfd_arch_bits_per_address(ss->parent->abfd)) {
1027 case 32:
1028 code = BFD_RELOC_32;
1029 break;
1030 case 64:
1031 code = BFD_RELOC_64;
1032 break;
1033 default:
1034 DIE;
1037 arelent *reloc = malloc(sizeof(*reloc));
1038 reloc->sym_ptr_ptr = symp;
1039 reloc->address = addr - ss->contents.data;
1040 reloc->howto = bfd_reloc_type_lookup(ss->parent->abfd, code);
1041 reloc->addend = offset;
1042 return reloc;
1045 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
1046 bfd_vma offset)
1048 arelent *new_reloc = create_reloc(ss, addr, symp, offset), **relocp;
1049 for (relocp = ss->relocs.data;
1050 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1051 if ((*relocp)->address == new_reloc->address) {
1052 memmove(relocp,
1053 relocp + 1,
1054 (void *)(ss->relocs.data + ss->relocs.size) -
1055 (void *)(relocp + 1));
1056 ss->relocs.size--;
1057 relocp--;
1060 *vec_grow(&ss->new_relocs, 1) = new_reloc;
1063 void write_string(struct supersect *ss, const char **addr, const char *fmt, ...)
1065 va_list ap;
1066 struct supersect *str_ss = make_section(ss->parent, ".ksplice_str");
1067 char *str;
1068 va_start(ap, fmt);
1069 int len = vasprintf(&str, fmt, ap);
1070 assert(len >= 0);
1071 va_end(ap);
1073 unsigned long *str_offp = ulong_hash_lookup(&ksplice_string_offset, str,
1074 FALSE);
1075 if (str_offp == NULL) {
1076 char *buf = sect_grow(str_ss, len + 1, char);
1077 memcpy(buf, str, len + 1);
1078 str_offp = ulong_hash_lookup(&ksplice_string_offset, str, TRUE);
1079 *str_offp = (void *)buf - str_ss->contents.data;
1082 write_reloc(ss, addr, &str_ss->symbol, *str_offp);
1085 void lookup_system_map(struct addr_vec *addrs, const char *name, long offset)
1087 struct addr_vec *map_addrs =
1088 addr_vec_hash_lookup(&system_map, name, FALSE);
1089 if (map_addrs == NULL)
1090 return;
1092 unsigned long *addr, *map_addr;
1093 for (map_addr = map_addrs->data;
1094 map_addr < map_addrs->data + map_addrs->size; map_addr++) {
1095 for (addr = addrs->data; addr < addrs->data + addrs->size;
1096 addr++) {
1097 if (*addr == *map_addr + offset)
1098 break;
1100 if (addr < addrs->data + addrs->size)
1101 continue;
1102 *vec_grow(addrs, 1) = *map_addr + offset;
1106 void write_system_map_array(struct superbfd *sbfd, struct supersect *ss,
1107 const unsigned long **sym_addrs,
1108 unsigned long *num_sym_addrs, asymbol *sym)
1110 struct addr_vec addrs;
1111 vec_init(&addrs);
1113 if (bfd_is_abs_section(sym->section)) {
1114 *vec_grow(&addrs, 1) = sym->value;
1115 } else if (bfd_is_und_section(sym->section)) {
1116 lookup_system_map(&addrs, sym->name, 0);
1117 } else if (!bfd_is_const_section(sym->section)) {
1118 asymbol **gsymp;
1119 for (gsymp = sbfd->syms.data;
1120 gsymp < sbfd->syms.data + sbfd->syms.size; gsymp++) {
1121 asymbol *gsym = *gsymp;
1122 if ((gsym->flags & BSF_DEBUGGING) == 0 &&
1123 gsym->section == sym->section)
1124 lookup_system_map(&addrs, gsym->name,
1125 sym->value - gsym->value);
1129 *num_sym_addrs = addrs.size;
1130 if (addrs.size != 0) {
1131 struct supersect *array_ss = make_section(sbfd,
1132 ".ksplice_array");
1133 void *buf = sect_grow(array_ss, addrs.size,
1134 typeof(*addrs.data));
1135 memcpy(buf, addrs.data, addrs.size * sizeof(*addrs.data));
1136 write_reloc(ss, sym_addrs, &array_ss->symbol,
1137 buf - array_ss->contents.data);
1138 } else {
1139 *sym_addrs = NULL;
1142 vec_free(&addrs);
1145 void write_ksplice_system_map(struct superbfd *sbfd, asymbol *sym,
1146 const char *addstr_sect)
1148 struct supersect *smap_ss = make_section(sbfd, ".ksplice_system_map");
1149 struct ksplice_system_map *smap;
1150 const char *label = label_lookup(sbfd, sym);
1152 bool *done = bool_hash_lookup(&system_map_written, label, TRUE);
1153 if (*done)
1154 return;
1155 *done = true;
1157 smap = sect_grow(smap_ss, 1, struct ksplice_system_map);
1159 write_system_map_array(sbfd, smap_ss, &smap->candidates,
1160 &smap->nr_candidates, sym);
1161 write_string(smap_ss, &smap->label, "%s%s", label, addstr_sect);
1164 void write_ksplice_symbol(struct supersect *ss,
1165 const struct ksplice_symbol *const *addr,
1166 asymbol *sym, const char *addstr_sect)
1168 struct supersect *ksymbol_ss = make_section(ss->parent,
1169 ".ksplice_symbols");
1170 struct ksplice_symbol *ksymbol;
1171 unsigned long *ksymbol_offp;
1172 const char *label = label_lookup(ss->parent, sym);
1173 char *output;
1174 assert(asprintf(&output, "%s%s", label, addstr_sect) >= 0);
1176 ksymbol_offp = ulong_hash_lookup(&ksplice_symbol_offset, output, FALSE);
1177 if (ksymbol_offp != NULL) {
1178 write_reloc(ss, addr, &ksymbol_ss->symbol, *ksymbol_offp);
1179 return;
1181 ksymbol = sect_grow(ksymbol_ss, 1, struct ksplice_symbol);
1182 ksymbol_offp = ulong_hash_lookup(&ksplice_symbol_offset, output, TRUE);
1183 *ksymbol_offp = (void *)ksymbol - ksymbol_ss->contents.data;
1185 if (bfd_is_und_section(sym->section) || (sym->flags & BSF_GLOBAL) != 0) {
1186 write_string(ksymbol_ss, &ksymbol->name, "%s", sym->name);
1187 } else if (bfd_is_const_section(sym->section)) {
1188 ksymbol->name = NULL;
1189 } else {
1190 asymbol *gsym = canonical_symbol(ss->parent, sym);
1192 if (gsym == NULL)
1193 ksymbol->name = NULL;
1194 else
1195 write_string(ksymbol_ss, &ksymbol->name, "%s",
1196 gsym->name);
1199 write_string(ksymbol_ss, &ksymbol->label, "%s%s", label, addstr_sect);
1201 write_ksplice_system_map(ksymbol_ss->parent, sym, addstr_sect);
1203 write_reloc(ss, addr, &ksymbol_ss->symbol, *ksymbol_offp);
1206 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc)
1208 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
1209 reloc_howto_type *howto = orig_reloc->howto;
1210 bfd_vma addend = get_reloc_offset(ss, orig_reloc, false);
1212 if (mode("finalize") && starts_with(ss->name, ".ksplice_patches")) {
1213 unsigned long *repladdr =
1214 ss->contents.data + orig_reloc->address;
1215 *repladdr = 0;
1216 return;
1219 blot_section(ss, orig_reloc->address, howto);
1221 struct supersect *kreloc_ss = make_section(ss->parent,
1222 mode("rmsyms") ?
1223 ".ksplice_init_relocs" :
1224 ".ksplice_relocs");
1225 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
1226 struct ksplice_reloc);
1228 write_reloc(kreloc_ss, &kreloc->blank_addr,
1229 &ss->symbol, orig_reloc->address);
1230 kreloc->blank_offset = (unsigned long)orig_reloc->address;
1231 write_ksplice_symbol(kreloc_ss, &kreloc->symbol, sym_ptr, "");
1232 kreloc->pcrel = howto->pc_relative;
1233 kreloc->addend = addend;
1234 kreloc->size = bfd_get_reloc_size(howto);
1235 kreloc->dst_mask = howto->dst_mask;
1236 kreloc->rightshift = howto->rightshift;
1237 kreloc->signed_addend =
1238 (howto->complain_on_overflow == complain_overflow_signed) ||
1239 (howto->complain_on_overflow == complain_overflow_bitfield);
1242 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
1244 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto)
1246 int bits = bfd_get_reloc_size(howto) * 8;
1247 void *address = ss->contents.data + offset;
1248 bfd_vma x = bfd_get(bits, ss->parent->abfd, address);
1249 x = (x & ~howto->dst_mask) |
1250 ((bfd_vma)KSPLICE_CANARY & howto->dst_mask);
1251 bfd_put(bits, ss->parent->abfd, x, address);
1254 void write_ksplice_section(struct superbfd *sbfd, asymbol **symp)
1256 asymbol *sym = *symp;
1257 struct supersect *ksect_ss = make_section(sbfd, ".ksplice_sections");
1258 struct ksplice_section *ksect = sect_grow(ksect_ss, 1,
1259 struct ksplice_section);
1261 write_ksplice_symbol(ksect_ss, &ksect->symbol, sym,
1262 mode("keep-primary") ? "(post)" : "");
1263 ksect->size = bfd_get_section_size(sym->section);
1264 ksect->flags = 0;
1265 if (starts_with(sym->section->name, ".rodata"))
1266 ksect->flags |= KSPLICE_SECTION_RODATA;
1267 if (starts_with(sym->section->name, ".data"))
1268 ksect->flags |= KSPLICE_SECTION_DATA;
1269 if (matchable_text_section(sbfd, sym->section))
1270 ksect->flags |= KSPLICE_SECTION_TEXT;
1271 assert(ksect->flags != 0);
1272 write_reloc(ksect_ss, &ksect->address, symp, 0);
1275 void write_ksplice_patch(struct superbfd *sbfd, const char *sectname)
1277 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
1278 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
1279 struct ksplice_patch);
1280 asection *sect = bfd_get_section_by_name(sbfd->abfd, sectname);
1281 assert(sect != NULL);
1283 write_string(kpatch_ss, &kpatch->label, "%s",
1284 label_lookup(sbfd, sect->symbol));
1285 write_reloc(kpatch_ss, &kpatch->repladdr, &sect->symbol, 0);
1288 void write_ksplice_deleted_patch(struct superbfd *sbfd, const char *name,
1289 const char *label)
1291 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
1292 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
1293 struct ksplice_patch);
1295 write_string(kpatch_ss, &kpatch->label, "%s", label);
1296 asymbol **symp;
1297 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
1298 symp++) {
1299 asymbol *sym = *symp;
1300 if (bfd_is_und_section(sym->section) &&
1301 strcmp(name, sym->name) == 0)
1302 break;
1304 if (symp >= sbfd->syms.data + sbfd->syms.size) {
1305 symp = malloc(sizeof(*symp));
1306 *symp = bfd_make_empty_symbol(sbfd->abfd);
1307 asymbol *sym = *symp;
1308 sym->name = strdup(name);
1309 sym->section = bfd_und_section_ptr;
1310 sym->flags = 0;
1311 sym->value = 0;
1312 *vec_grow(&sbfd->new_syms, 1) = symp;
1314 write_reloc(kpatch_ss, &kpatch->repladdr, symp, 0);
1317 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
1318 const char *export_type, bool del)
1320 struct supersect *export_ss = make_section(sbfd, ".ksplice_exports");
1321 struct ksplice_export *exp = sect_grow(export_ss, 1,
1322 struct ksplice_export);
1324 if (del) {
1325 write_string(export_ss, &exp->name, "%s", symname);
1326 write_string(export_ss, &exp->new_name, "DISABLED_%s_%s",
1327 symname, kid);
1328 } else {
1329 write_string(export_ss, &exp->new_name, "%s", symname);
1330 write_string(export_ss, &exp->name, "DISABLED_%s_%s", symname,
1331 kid);
1335 struct fixup_entry {
1336 bfd_vma offset;
1337 bool used;
1338 bfd_vma ex_offset;
1340 DECLARE_VEC_TYPE(struct fixup_entry, fixup_entry_vec);
1342 int compare_fixups(const void *aptr, const void *bptr)
1344 const struct fixup_entry *a = aptr, *b = bptr;
1345 if (a->offset < b->offset)
1346 return -1;
1347 else if (a->offset > b->offset)
1348 return 1;
1349 else
1350 return (int)a->used - (int)b->used;
1353 void filter_table_sections(struct superbfd *isbfd)
1355 struct supersect *tables_ss =
1356 fetch_supersect(offsets_sbfd,
1357 bfd_get_section_by_name(offsets_sbfd->abfd,
1358 ".ksplice_table_sections"));
1359 const struct table_section *ts;
1360 for (ts = tables_ss->contents.data;
1361 (void *)ts < tables_ss->contents.data + tables_ss->contents.size;
1362 ts++) {
1363 struct table_section s = *ts;
1364 s.sect = read_string(tables_ss, &ts->sect);
1365 s.other_sect = read_string(tables_ss, &ts->other_sect);
1366 filter_table_section(isbfd, &s);
1370 void filter_table_section(struct superbfd *sbfd, const struct table_section *s)
1372 asection *isection = bfd_get_section_by_name(sbfd->abfd, s->sect);
1373 if (isection == NULL)
1374 return;
1375 asection *fixup_sect = NULL;
1376 if (s->other_sect != NULL)
1377 fixup_sect = bfd_get_section_by_name(sbfd->abfd, s->other_sect);
1379 struct supersect *ss = fetch_supersect(sbfd, isection), orig_ss;
1380 supersect_move(&orig_ss, ss);
1382 struct supersect *fixup_ss = NULL;
1383 if (fixup_sect != NULL)
1384 fixup_ss = fetch_supersect(sbfd, fixup_sect);
1386 struct fixup_entry_vec fixups;
1387 vec_init(&fixups);
1389 void *orig_entry;
1390 for (orig_entry = orig_ss.contents.data;
1391 orig_entry < orig_ss.contents.data + orig_ss.contents.size;
1392 orig_entry += s->entry_size) {
1393 asymbol *sym, *fixup_sym;
1394 read_reloc(&orig_ss, orig_entry + s->addr_offset,
1395 sizeof(void *), &sym);
1397 struct fixup_entry *f;
1398 if (fixup_sect != NULL) {
1399 bfd_vma fixup_offset =
1400 read_reloc(&orig_ss, orig_entry + s->other_offset,
1401 sizeof(void *), &fixup_sym);
1402 if (fixup_sym->section == fixup_sect) {
1403 assert(fixup_offset < fixup_ss->contents.size);
1404 f = vec_grow(&fixups, 1);
1405 f->offset = fixup_offset;
1406 f->used = false;
1410 struct supersect *sym_ss = fetch_supersect(sbfd, sym->section);
1411 if (!sym_ss->keep)
1412 continue;
1414 if (fixup_sect != NULL && fixup_sym->section == fixup_sect) {
1415 f->used = true;
1416 f->ex_offset = ss->contents.size + s->other_offset;
1418 sect_copy(ss, sect_do_grow(ss, 1, s->entry_size,
1419 s->entry_align),
1420 &orig_ss, orig_entry, s->entry_size);
1423 if (fixup_sect == NULL)
1424 return;
1426 struct supersect orig_fixup_ss;
1427 supersect_move(&orig_fixup_ss, fixup_ss);
1429 qsort(fixups.data, fixups.size, sizeof(*fixups.data), compare_fixups);
1430 *vec_grow(&fixups, 1) = (struct fixup_entry)
1431 { .offset = orig_fixup_ss.contents.size, .used = false };
1433 struct fixup_entry *f;
1434 for (f = fixups.data; f < fixups.data + fixups.size - 1; f++) {
1435 if (!f->used)
1436 continue;
1437 write_reloc(ss, ss->contents.data + f->ex_offset,
1438 &fixup_ss->symbol, fixup_ss->contents.size);
1439 sect_copy(fixup_ss,
1440 sect_grow(fixup_ss, (f + 1)->offset - f->offset,
1441 unsigned char),
1442 &orig_fixup_ss,
1443 orig_fixup_ss.contents.data + f->offset,
1444 (f + 1)->offset - f->offset);
1448 void keep_if_referenced(bfd *abfd, asection *sect, void *ignored)
1450 struct superbfd *sbfd = fetch_superbfd(abfd);
1451 struct supersect *ss = fetch_supersect(sbfd, sect);
1452 if (ss->keep || ignored_section(sbfd, sect))
1453 return;
1455 asymbol **symp;
1456 for (symp = sbfd->syms.data;
1457 symp < sbfd->syms.data + sbfd->syms.size; symp++) {
1458 asymbol *sym = *symp;
1459 if (sym->section == sect && (sym->flags & BSF_GLOBAL) != 0) {
1460 ss->keep = true;
1461 changed = true;
1462 return;
1466 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
1469 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
1470 void *looking_for)
1472 struct superbfd *sbfd = fetch_superbfd(abfd);
1473 struct supersect *ss = fetch_supersect(sbfd, looking_at);
1474 struct supersect *for_ss = fetch_supersect(sbfd,
1475 (asection *)looking_for);
1476 if (!ss->keep || is_table_section(looking_at)
1477 || strcmp(looking_at->name, ".fixup") == 0)
1478 return;
1480 arelent **relocp;
1481 for (relocp = ss->relocs.data;
1482 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1483 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1484 if (sym->section != (asection *)looking_for)
1485 continue;
1486 for_ss->keep = true;
1487 changed = true;
1488 return;
1492 void copy_symbols(struct asymbolp_vec *osyms, struct asymbolpp_vec *isyms)
1494 asymbol ***sympp;
1495 for (sympp = isyms->data; sympp < isyms->data + isyms->size; sympp++)
1496 *vec_grow(osyms, 1) = **sympp;
1499 /* Modified function from GNU Binutils objcopy.c */
1500 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
1502 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
1504 bfd_vma start = bfd_get_start_address(ibfd);
1506 flagword flags = bfd_get_file_flags(ibfd);
1507 flags &= bfd_applicable_file_flags(obfd);
1509 assert(bfd_set_start_address(obfd, start)
1510 && bfd_set_file_flags(obfd, flags));
1512 enum bfd_architecture iarch = bfd_get_arch(ibfd);
1513 unsigned int imach = bfd_get_mach(ibfd);
1514 assert(bfd_set_arch_mach(obfd, iarch, imach));
1515 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
1517 /* BFD mandates that all output sections be created and sizes set before
1518 any output is done. Thus, we traverse all sections multiple times. */
1519 bfd_map_over_sections(ibfd, setup_section, obfd);
1521 struct supersect *new_supersects = fetch_superbfd(ibfd)->new_supersects;
1522 struct supersect *ss;
1523 for (ss = new_supersects; ss != NULL; ss = ss->next)
1524 setup_new_section(obfd, ss);
1526 /* Mark symbols used in output relocations so that they
1527 are kept, even if they are local labels or static symbols.
1529 Note we iterate over the input sections examining their
1530 relocations since the relocations for the output sections
1531 haven't been set yet. mark_symbols_used_in_relocations will
1532 ignore input sections which have no corresponding output
1533 section. */
1535 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, NULL);
1536 for (ss = new_supersects; ss != NULL; ss = ss->next)
1537 ss_mark_symbols_used_in_relocations(ss);
1538 struct asymbolp_vec osyms;
1539 vec_init(&osyms);
1540 filter_symbols(ibfd, obfd, &osyms, &fetch_superbfd(ibfd)->syms);
1541 copy_symbols(&osyms, &fetch_superbfd(ibfd)->new_syms);
1543 bfd_set_symtab(obfd, osyms.data, osyms.size);
1545 /* This has to happen after the symbol table has been set. */
1546 bfd_map_over_sections(obfd, write_section, NULL);
1548 /* Allow the BFD backend to copy any private data it understands
1549 from the input BFD to the output BFD. This is done last to
1550 permit the routine to look at the filtered symbol table, which is
1551 important for the ECOFF code at least. */
1552 assert(bfd_copy_private_bfd_data(ibfd, obfd));
1554 return TRUE;
1557 /* Modified function from GNU Binutils objcopy.c */
1558 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
1560 struct superbfd *isbfd = fetch_superbfd(ibfd);
1561 struct supersect *ss = fetch_supersect(isbfd, isection);
1562 bfd *obfd = obfdarg;
1563 bfd_vma vma;
1565 if (!ss->keep)
1566 return;
1568 asection *osection = bfd_make_section_anyway(obfd, isection->name);
1569 assert(osection != NULL);
1571 osection->userdata = ss;
1572 bfd_set_section_flags(obfd, osection, ss->flags);
1573 ss->symbol = osection->symbol;
1574 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
1576 vma = bfd_section_vma(ibfd, isection);
1577 assert(bfd_set_section_vma(obfd, osection, vma));
1579 osection->lma = isection->lma;
1580 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
1581 osection->entsize = isection->entsize;
1582 osection->output_section = osection;
1583 osection->output_offset = 0;
1584 isection->output_section = osection;
1585 isection->output_offset = 0;
1586 return;
1589 void setup_new_section(bfd *obfd, struct supersect *ss)
1591 asection *osection = bfd_make_section_anyway(obfd, ss->name);
1592 assert(osection != NULL);
1593 bfd_set_section_flags(obfd, osection, ss->flags);
1595 osection->userdata = ss;
1596 ss->symbol = osection->symbol;
1597 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
1598 assert(bfd_set_section_vma(obfd, osection, 0));
1600 osection->lma = 0;
1601 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
1602 osection->entsize = 0;
1603 osection->output_section = osection;
1604 osection->output_offset = 0;
1607 void write_section(bfd *obfd, asection *osection, void *arg)
1609 struct supersect *ss = osection->userdata;
1611 if ((ss->flags & SEC_GROUP) != 0 || ss->contents.size == 0)
1612 return;
1614 arelent **relocp;
1615 char *error_message;
1616 for (relocp = ss->new_relocs.data;
1617 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
1618 bfd_vma val;
1619 if (bfd_get_arch(obfd) == bfd_arch_arm)
1620 val = osection->use_rela_p ? 0 : (*relocp)->addend;
1621 else
1622 val = 0;
1623 bfd_put(bfd_get_reloc_size((*relocp)->howto) * 8, obfd, val,
1624 ss->contents.data + (*relocp)->address);
1625 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
1626 0, osection, &error_message) !=
1627 bfd_reloc_ok) {
1628 fprintf(stderr, "ksplice: error installing reloc: %s",
1629 error_message);
1630 DIE;
1633 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
1634 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
1636 bfd_set_reloc(obfd, osection,
1637 ss->relocs.size == 0 ? NULL : ss->relocs.data,
1638 ss->relocs.size);
1640 if (ss->flags & SEC_HAS_CONTENTS)
1641 assert(bfd_set_section_contents
1642 (obfd, osection, ss->contents.data, 0,
1643 ss->contents.size));
1646 /* Modified function from GNU Binutils objcopy.c
1648 * Mark all the symbols which will be used in output relocations with
1649 * the BSF_KEEP flag so that those symbols will not be stripped.
1651 * Ignore relocations which will not appear in the output file.
1653 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
1654 void *ignored)
1656 struct superbfd *sbfd = fetch_superbfd(abfd);
1657 if (isection->output_section == NULL)
1658 return;
1660 struct supersect *ss = fetch_supersect(sbfd, isection);
1661 ss_mark_symbols_used_in_relocations(ss);
1664 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
1666 /* Examine each symbol used in a relocation. If it's not one of the
1667 special bfd section symbols, then mark it with BSF_KEEP. */
1668 arelent **relocp;
1669 for (relocp = ss->relocs.data;
1670 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1671 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1672 if (!(bfd_is_const_section(sym->section) &&
1673 sym == sym->section->symbol))
1674 sym->flags |= BSF_KEEP;
1676 for (relocp = ss->new_relocs.data;
1677 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
1678 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1679 if (!(bfd_is_const_section(sym->section) &&
1680 sym == sym->section->symbol))
1681 sym->flags |= BSF_KEEP;
1685 static bool deleted_table_section_symbol(bfd *abfd, asymbol *sym)
1687 struct superbfd *sbfd = fetch_superbfd(abfd);
1688 if (bfd_is_const_section(sym->section))
1689 return false;
1690 struct supersect *ss = fetch_supersect(sbfd, sym->section);
1692 asymbol **symp;
1693 for (symp = ss->syms.data; symp < ss->syms.data + ss->syms.size; symp++) {
1694 if (sym == *symp)
1695 break;
1697 return symp >= ss->syms.data + ss->syms.size;
1700 /* Modified function from GNU Binutils objcopy.c
1702 * Choose which symbol entries to copy.
1703 * We don't copy in place, because that confuses the relocs.
1704 * Return the number of symbols to print.
1706 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
1707 struct asymbolp_vec *isyms)
1709 asymbol **symp;
1710 struct superbfd *sbfd = fetch_superbfd(ibfd);
1711 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
1712 asymbol *sym = *symp;
1713 struct supersect *sym_ss = NULL;
1714 if (!bfd_is_const_section(sym->section))
1715 sym_ss = fetch_supersect(sbfd, sym->section);
1717 bool keep = false;
1719 if (mode("keep") && (sym->flags & BSF_GLOBAL) != 0 &&
1720 !(mode("keep-primary") && sym_ss != NULL && sym_ss->new))
1721 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
1723 if (mode("finalize") && (sym->flags & BSF_GLOBAL) != 0)
1724 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
1726 if ((sym->flags & BSF_KEEP) != 0 /* Used in relocation. */
1727 || ((sym->flags & BSF_SECTION_SYM) != 0 && sym_ss != NULL &&
1728 sym_ss->keep))
1729 keep = true;
1730 else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 &&
1731 sym_ss != NULL && sym_ss->keep)
1732 keep = true;
1733 else if (mode("keep-primary") &&
1734 starts_with(sym->section->name, "__ksymtab"))
1735 keep = true;
1737 if (deleted_table_section_symbol(ibfd, sym))
1738 keep = false;
1740 if (bfd_is_com_section(sym->section))
1741 keep = false;
1743 if (mode("rmsyms"))
1744 keep = !str_in_set(sym->name, &rmsyms);
1746 if (keep) {
1747 assert(sym_ss == NULL || sym_ss->keep);
1748 *vec_grow(osyms, 1) = sym;
1753 void read_str_set(struct str_vec *strs)
1755 char *buf = NULL;
1756 size_t n = 0;
1757 assert(getline(&buf, &n, stdin) >= 0);
1758 vec_init(strs);
1759 char *saveptr;
1760 while (1) {
1761 char *str = strtok_r(buf, " \n", &saveptr);
1762 buf = NULL;
1763 if (str == NULL)
1764 break;
1765 *vec_grow(strs, 1) = str;
1769 bool str_in_set(const char *str, const struct str_vec *strs)
1771 const char **strp;
1772 for (strp = strs->data; strp < strs->data + strs->size; strp++) {
1773 if (strcmp(str, *strp) == 0)
1774 return true;
1776 return false;
1779 bool is_table_section(asection *sect)
1781 if (!mode("keep") && !mode("finalize"))
1782 return false;
1784 struct supersect *tables_ss =
1785 fetch_supersect(offsets_sbfd, bfd_get_section_by_name(
1786 offsets_sbfd->abfd, ".ksplice_table_sections"));
1787 const struct table_section *ts;
1788 for (ts = tables_ss->contents.data;
1789 (void *)ts < tables_ss->contents.data + tables_ss->contents.size;
1790 ts++) {
1791 if (strcmp(sect->name, read_string(tables_ss, &ts->sect)) == 0)
1792 return true;
1794 return false;
1797 bool is_special(asection *sect)
1799 static const char *static_want[] = {
1800 ".altinstructions",
1801 ".altinstr_replacement",
1802 ".smp_locks",
1803 ".parainstructions",
1804 "__ex_table",
1805 ".fixup",
1806 "__bug_table",
1807 NULL
1810 int i;
1811 for (i = 0; static_want[i] != NULL; i++) {
1812 if (strcmp(sect->name, static_want[i]) == 0)
1813 return true;
1816 if (starts_with(sect->name, ".rodata.str"))
1817 return true;
1818 if (starts_with(sect->name, "__ksymtab"))
1819 return true;
1820 if (starts_with(sect->name, "__kcrctab"))
1821 return true;
1822 return false;