Add System.map reading code to objmanip.
[ksplice.git] / objdiff.c
blob33377d4eb4e98be8e15fc44bede6e0dbddbf3527
1 /* Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License, version 2.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
14 * 02110-1301, USA.
18 * "objdiff old.o new.o" prints two lists to STDOUT, one per line:
19 * (1) the names of the ELF sections in new.o that either
20 * (a) do not appear in old.o, or
21 * (b) have different contents in old.o and new.o
22 * (2) the names of the "entry point" ELF symbols in new.o
23 * corresponding to the ELF sections in list (1)
25 * Before printing these two lists, objdiff prints the number of bits
26 * per address on the target architecture.
29 #include "objcommon.h"
30 #include "objdiff.h"
32 bfd *newbfd;
33 struct asymbolp_vec new_syms, old_syms;
35 int main(int argc, char **argv)
37 bfd_init();
38 bfd *oldbfd = bfd_openr(argv[1], NULL);
39 assert(oldbfd != NULL);
40 newbfd = bfd_openr(argv[2], NULL);
41 assert(newbfd != NULL);
43 char **matching;
44 assert(bfd_check_format_matches(oldbfd, bfd_object, &matching));
45 assert(bfd_check_format_matches(newbfd, bfd_object, &matching));
47 get_syms(newbfd, &new_syms);
48 get_syms(oldbfd, &old_syms);
50 printf("%d\n", bfd_arch_bits_per_address(oldbfd));
51 foreach_nonmatching(oldbfd, newbfd, print_newbfd_section_name);
52 printf("\n");
53 foreach_nonmatching(oldbfd, newbfd, print_newbfd_entry_symbols);
54 printf("\n");
56 assert(bfd_close(oldbfd));
57 assert(bfd_close(newbfd));
58 return EXIT_SUCCESS;
61 void foreach_nonmatching(bfd *oldbfd, bfd *newbfd, section_fn s_fn)
63 asection *newp, *oldp;
64 for (newp = newbfd->sections; newp != NULL; newp = newp->next) {
65 if (!starts_with(newp->name, ".text"))
66 continue;
67 oldp = bfd_get_section_by_name(oldbfd, newp->name);
68 if (oldp == NULL) {
69 if (s_fn == print_newbfd_section_name)
70 s_fn(newp);
71 continue;
73 int newsize = bfd_get_section_size(newp);
74 int oldsize = bfd_get_section_size(oldp);
75 if (newsize == oldsize) {
76 void *newmem = malloc(newsize);
77 void *oldmem = malloc(oldsize);
78 assert(bfd_get_section_contents
79 (oldbfd, oldp, oldmem, 0, oldsize));
80 assert(bfd_get_section_contents
81 (newbfd, newp, newmem, 0, newsize));
82 if (memcmp(newmem, oldmem, newsize) == 0 &&
83 reloc_cmp(oldbfd, oldp, newbfd, newp) == 0)
84 continue;
86 s_fn(newp);
91 * reloc_cmp checks to see whether the old section and the new section
92 * reference different read-only data in their relocations -- if a hard-coded
93 * string has been changed between the old file and the new file, reloc_cmp
94 * will detect the difference.
96 int reloc_cmp(bfd *oldbfd, asection *oldp, bfd *newbfd, asection *newp)
98 int i;
99 struct supersect *old_ss, *new_ss;
101 old_ss = fetch_supersect(oldbfd, oldp, &old_syms);
102 new_ss = fetch_supersect(newbfd, newp, &new_syms);
104 if (old_ss->relocs.size != new_ss->relocs.size)
105 return -1;
107 for (i = 0; i < old_ss->relocs.size; i++) {
108 struct supersect *ro_old_ss, *ro_new_ss;
110 asection *ro_oldp =
111 (*old_ss->relocs.data[i]->sym_ptr_ptr)->section;
112 asection *ro_newp =
113 (*new_ss->relocs.data[i]->sym_ptr_ptr)->section;
115 ro_old_ss = fetch_supersect(oldbfd, ro_oldp, &old_syms);
116 ro_new_ss = fetch_supersect(newbfd, ro_newp, &new_syms);
118 if (!starts_with(ro_old_ss->name, ".rodata"))
119 continue;
121 if (strcmp(ro_old_ss->name, ro_new_ss->name) != 0)
122 return -1;
124 int old_offset = *(int *)(old_ss->contents.data +
125 old_ss->relocs.data[i]->address);
126 int new_offset = *(int *)(new_ss->contents.data +
127 new_ss->relocs.data[i]->address);
129 if (starts_with(ro_old_ss->name, ".rodata.str")) {
130 if (strcmp
131 (ro_old_ss->contents.data + old_offset,
132 ro_new_ss->contents.data + new_offset) != 0)
133 return -1;
134 continue;
137 if (ro_old_ss->contents.size != ro_new_ss->contents.size)
138 return -1;
140 if (memcmp(ro_old_ss->contents.data, ro_new_ss->contents.data,
141 ro_old_ss->contents.size) != 0)
142 return -1;
145 return 0;
148 void print_newbfd_section_name(asection *sect)
150 printf("%s ", sect->name);
153 void print_newbfd_entry_symbols(asection *sect)
155 asymbol **symp;
156 for (symp = new_syms.data; symp < new_syms.data + new_syms.size;
157 symp++) {
158 asymbol *sym = *symp;
159 if (strlen(sym->name) != 0 &&
160 !starts_with(sym->name, ".text") &&
161 strcmp(sym->section->name, sect->name) == 0)
162 printf("%s ", sym->name);