Make sure objmanip rmsyms succeeds.
[ksplice.git] / objdiff.c
blobd294ca6246481380c90e9284ccc0e1323f1b143f
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"
31 #define symbol_init(sym) *(sym) = (asymbol *)NULL
32 DEFINE_HASH_TYPE(asymbol *, symbol_hash, symbol_hash_init, symbol_hash_free,
33 symbol_hash_lookup, symbol_init);
35 struct export {
36 const char *name;
37 asection *sect;
39 DECLARE_VEC_TYPE(struct export, export_vec);
41 void foreach_nonmatching(struct superbfd *oldsbfd, struct superbfd *newsbfd,
42 void (*s_fn)(struct supersect *));
43 void compare_symbols(struct superbfd *oldsbfd, struct superbfd *newsbfd,
44 flagword flags);
45 struct export_vec *get_export_syms(struct superbfd *sbfd);
46 void compare_exported_symbols(struct superbfd *oldsbfd,
47 struct superbfd *newsbfd, char *addstr);
48 int reloc_cmp(struct superbfd *oldsbfd, asection *oldp,
49 struct superbfd *newsbfd, asection *newp);
50 static void print_newbfd_section_name(struct supersect *ss);
51 static void print_newbfd_entry_symbols(struct supersect *ss);
53 int main(int argc, char *argv[])
55 bfd_init();
56 bfd *oldbfd = bfd_openr(argv[1], NULL);
57 assert(oldbfd != NULL);
58 bfd *newbfd = bfd_openr(argv[2], NULL);
59 assert(newbfd != NULL);
61 char **matching;
62 assert(bfd_check_format_matches(oldbfd, bfd_object, &matching));
63 assert(bfd_check_format_matches(newbfd, bfd_object, &matching));
65 struct superbfd *oldsbfd = fetch_superbfd(oldbfd);
66 struct superbfd *newsbfd = fetch_superbfd(newbfd);
68 foreach_nonmatching(oldsbfd, newsbfd, print_newbfd_section_name);
69 printf("\n");
70 foreach_nonmatching(oldsbfd, newsbfd, print_newbfd_entry_symbols);
71 printf("\n");
72 compare_symbols(oldsbfd, newsbfd, ~0);
73 printf("\n");
74 compare_symbols(newsbfd, oldsbfd, BSF_FUNCTION);
75 compare_exported_symbols(oldsbfd, newsbfd, "");
76 compare_exported_symbols(newsbfd, oldsbfd, "del_");
77 printf("\n");
79 assert(bfd_close(oldbfd));
80 assert(bfd_close(newbfd));
81 return EXIT_SUCCESS;
84 struct export_vec *get_export_syms(struct superbfd *sbfd)
86 asection *sect;
87 struct export_vec *exports;
88 exports = malloc(sizeof(*exports));
89 assert(exports != NULL);
90 vec_init(exports);
92 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
93 if (!starts_with(sect->name, "__ksymtab") ||
94 ends_with(sect->name, "_strings"))
95 continue;
96 struct supersect *ss = fetch_supersect(sbfd, sect);
97 struct kernel_symbol *sym;
98 assert(ss->contents.size * 2 == ss->relocs.size *
99 sizeof(struct kernel_symbol));
100 for (sym = ss->contents.data;
101 (void *)sym < ss->contents.data + ss->contents.size;
102 sym++) {
103 struct export *exp = vec_grow(exports, 1);
104 exp->name =
105 read_string(ss, (const char *const *)&sym->name);
106 exp->sect = sect;
109 return exports;
112 void compare_exported_symbols(struct superbfd *oldsbfd,
113 struct superbfd *newsbfd, char *addstr)
115 struct export_vec *new_exports, *old_exports;
116 new_exports = get_export_syms(newsbfd);
117 if (new_exports == NULL)
118 return;
119 old_exports = get_export_syms(oldsbfd);
120 struct export *old, *new;
121 int found;
122 asection *last_sect = NULL;
123 for (new = new_exports->data; new < new_exports->data +
124 new_exports->size; new++) {
125 found = 0;
126 if (old_exports != NULL) {
127 for (old = old_exports->data; old < old_exports->data +
128 old_exports->size; old++) {
129 if (strcmp(new->name, old->name) == 0 &&
130 strcmp(new->sect->name, old->sect->name)
131 == 0) {
132 found = 1;
133 break;
137 /* last_sect can go away once we make objdiff | objmanip */
138 if (last_sect != new->sect) {
139 last_sect = new->sect;
140 printf("\n%s%s", addstr, new->sect->name);
142 if (found == 0)
143 printf(" %s", new->name);
147 void compare_symbols(struct superbfd *oldsbfd, struct superbfd *newsbfd,
148 flagword flags)
150 asymbol **old, **new, **tmp;
151 struct symbol_hash old_hash;
152 symbol_hash_init(&old_hash);
153 for (old = oldsbfd->syms.data; old < oldsbfd->syms.data +
154 oldsbfd->syms.size; old++) {
155 if (((*old)->flags & flags) == 0 ||
156 ((*old)->flags & BSF_DEBUGGING) != 0)
157 continue;
158 tmp = symbol_hash_lookup(&old_hash, (*old)->name, TRUE);
159 if (*tmp != NULL) {
160 fprintf(stderr, "Two global symbols named %s!\n",
161 (*old)->name);
162 DIE;
164 *tmp = *old;
166 for (new = newsbfd->syms.data; new < newsbfd->syms.data +
167 newsbfd->syms.size; new++) {
168 if (((*new)->flags & flags) == 0 ||
169 ((*new)->flags & BSF_DEBUGGING) != 0)
170 continue;
171 tmp = symbol_hash_lookup(&old_hash, (*new)->name, FALSE);
172 if (tmp == NULL)
173 printf("%s ", (*new)->name);
175 symbol_hash_free(&old_hash);
178 void foreach_nonmatching(struct superbfd *oldsbfd, struct superbfd *newsbfd,
179 void (*s_fn)(struct supersect *))
181 asection *newp, *oldp;
182 struct supersect *old_ss, *new_ss;
183 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
184 if (!starts_with(newp->name, ".text"))
185 continue;
186 new_ss = fetch_supersect(newsbfd, newp);
187 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
188 if (oldp == NULL) {
189 if (s_fn == print_newbfd_section_name)
190 s_fn(new_ss);
191 continue;
193 old_ss = fetch_supersect(oldsbfd, oldp);
194 if (new_ss->contents.size == old_ss->contents.size &&
195 memcmp(new_ss->contents.data, old_ss->contents.data,
196 new_ss->contents.size) == 0 &&
197 reloc_cmp(oldsbfd, oldp, newsbfd, newp) == 0)
198 continue;
199 s_fn(new_ss);
204 * reloc_cmp checks to see whether the old section and the new section
205 * reference different read-only data in their relocations -- if a hard-coded
206 * string has been changed between the old file and the new file, reloc_cmp
207 * will detect the difference.
209 int reloc_cmp(struct superbfd *oldsbfd, asection *oldp,
210 struct superbfd *newsbfd, asection *newp)
212 int i;
213 struct supersect *old_ss, *new_ss;
215 old_ss = fetch_supersect(oldsbfd, oldp);
216 new_ss = fetch_supersect(newsbfd, newp);
218 if (old_ss->relocs.size != new_ss->relocs.size)
219 return -1;
221 for (i = 0; i < old_ss->relocs.size; i++) {
222 struct supersect *ro_old_ss, *ro_new_ss;
224 asection *ro_oldp =
225 (*old_ss->relocs.data[i]->sym_ptr_ptr)->section;
226 asection *ro_newp =
227 (*new_ss->relocs.data[i]->sym_ptr_ptr)->section;
229 ro_old_ss = fetch_supersect(oldsbfd, ro_oldp);
230 ro_new_ss = fetch_supersect(newsbfd, ro_newp);
232 if (!starts_with(ro_old_ss->name, ".rodata"))
233 continue;
235 if (strcmp(ro_old_ss->name, ro_new_ss->name) != 0)
236 return -1;
238 bfd_vma old_offset = get_reloc_offset(old_ss,
239 old_ss->relocs.data[i],
241 bfd_vma new_offset = get_reloc_offset(new_ss,
242 new_ss->relocs.data[i],
245 if (starts_with(ro_old_ss->name, ".rodata.str")) {
246 if (strcmp
247 (ro_old_ss->contents.data + old_offset,
248 ro_new_ss->contents.data + new_offset) != 0)
249 return -1;
250 continue;
253 if (ro_old_ss->contents.size != ro_new_ss->contents.size)
254 return -1;
256 if (memcmp(ro_old_ss->contents.data, ro_new_ss->contents.data,
257 ro_old_ss->contents.size) != 0)
258 return -1;
261 return 0;
264 void print_newbfd_section_name(struct supersect *ss)
266 printf("%s ", ss->name);
269 void print_newbfd_entry_symbols(struct supersect *ss)
271 struct asymbolp_vec new_syms = ss->parent->syms;
272 asymbol **symp;
273 for (symp = new_syms.data; symp < new_syms.data + new_syms.size;
274 symp++) {
275 asymbol *sym = *symp;
276 struct supersect *sym_ss = fetch_supersect(ss->parent,
277 sym->section);
278 if (sym_ss != ss || sym->name[0] == '\0' ||
279 starts_with(sym->name, ".text"))
280 continue;
281 if (sym->value != 0) {
282 fprintf(stderr,
283 "Symbol %s [%x] has nonzero value %lx\n",
284 sym->name, sym->flags, sym->value);
285 DIE;
287 printf("%s ", sym->name);