Clean up loop in apply_update.
[ksplice.git] / objdiff.c
blob83f750debe5005f8593a9bab164896f048c90f21
1 /* Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
2 * Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
3 * Tim Abbott <tabbott@mit.edu>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
16 * 02110-1301, USA.
20 * "objdiff old.o new.o" prints to STDOUT the following, one per line:
21 * - several pairs of the form "<a> <b>;", where <a> and <b> are strings
22 * containing the Ksplice labels for sections symbols whose Ksplice labels
23 * differ between old.o and new.o.
24 * - the names of the ELF text sections in new.o that have different contents
25 * in old.o and new.o.
26 * - the names of the ELF sections in new.o that are not present in old.o.
27 * - the Ksplice labels for the section symbols of the ELF sections in old.o
28 * that are not present in new.o.
29 * - several lines beginning with either __ksymtab* or ___del_ksymtab*
30 * (where the * can be one of nothing, _gpl, _unused, _unused_gpl, etc.),
31 * consisting of lists of exported symbols that are in new.o but not old.o,
32 * or in old.o but not new.o, respectively.
34 * objdiff treats text sections that reference changed rodata sections as having
35 * changed, and rodata sections that have changed as being both new and deleted.
38 #include "objcommon.h"
40 #define symbol_init(sym) *(sym) = (asymbol *)NULL
41 DEFINE_HASH_TYPE(asymbol *, symbol_hash, symbol_hash_init, symbol_hash_free,
42 symbol_hash_lookup, symbol_init);
44 struct export {
45 const char *name;
46 asection *sect;
48 DECLARE_VEC_TYPE(struct export, export_vec);
50 void foreach_nonmatching(struct superbfd *oldsbfd, struct superbfd *newsbfd,
51 void (*s_fn)(struct superbfd *, asection *));
52 void foreach_new_section(struct superbfd *oldsbfd, struct superbfd *newsbfd,
53 void (*s_fn)(struct superbfd *, asection *));
54 void print_newbfd_section_name(struct superbfd *sbfd, asection *sect);
55 void print_newbfd_symbol_label(struct superbfd *sbfd, asection *sect);
56 struct export_vec *get_export_syms(struct superbfd *sbfd);
57 void compare_exported_symbols(struct superbfd *oldsbfd,
58 struct superbfd *newsbfd, char *addstr);
59 int reloc_cmp(struct superbfd *oldsbfd, asection *oldp,
60 struct superbfd *newsbfd, asection *newp);
61 static void print_section_symbol_renames(struct superbfd *oldsbfd,
62 struct superbfd *newsbfd);
64 int main(int argc, char *argv[])
66 bfd_init();
67 bfd *oldbfd = bfd_openr(argv[1], NULL);
68 assert(oldbfd != NULL);
69 bfd *newbfd = bfd_openr(argv[2], NULL);
70 assert(newbfd != NULL);
72 char **matching;
73 assert(bfd_check_format_matches(oldbfd, bfd_object, &matching));
74 assert(bfd_check_format_matches(newbfd, bfd_object, &matching));
76 struct superbfd *oldsbfd = fetch_superbfd(oldbfd);
77 struct superbfd *newsbfd = fetch_superbfd(newbfd);
79 print_section_symbol_renames(oldsbfd, newsbfd);
80 foreach_nonmatching(oldsbfd, newsbfd, print_newbfd_section_name);
81 printf("\n");
82 foreach_new_section(oldsbfd, newsbfd, print_newbfd_section_name);
83 printf("\n");
84 foreach_new_section(newsbfd, oldsbfd, print_newbfd_symbol_label);
85 compare_exported_symbols(oldsbfd, newsbfd, "");
86 compare_exported_symbols(newsbfd, oldsbfd, "del_");
87 printf("\n");
89 assert(bfd_close(oldbfd));
90 assert(bfd_close(newbfd));
91 return EXIT_SUCCESS;
94 struct export_vec *get_export_syms(struct superbfd *sbfd)
96 asection *sect;
97 struct export_vec *exports;
98 exports = malloc(sizeof(*exports));
99 assert(exports != NULL);
100 vec_init(exports);
102 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
103 if (!starts_with(sect->name, "__ksymtab") ||
104 ends_with(sect->name, "_strings"))
105 continue;
106 struct supersect *ss = fetch_supersect(sbfd, sect);
107 struct kernel_symbol *sym;
108 assert(ss->contents.size * 2 == ss->relocs.size *
109 sizeof(struct kernel_symbol));
110 for (sym = ss->contents.data;
111 (void *)sym < ss->contents.data + ss->contents.size;
112 sym++) {
113 struct export *exp = vec_grow(exports, 1);
114 exp->name =
115 read_string(ss, (const char *const *)&sym->name);
116 exp->sect = sect;
119 return exports;
122 void compare_exported_symbols(struct superbfd *oldsbfd,
123 struct superbfd *newsbfd, char *addstr)
125 struct export_vec *new_exports, *old_exports;
126 new_exports = get_export_syms(newsbfd);
127 if (new_exports == NULL)
128 return;
129 old_exports = get_export_syms(oldsbfd);
130 struct export *old, *new;
131 int found;
132 asection *last_sect = NULL;
133 for (new = new_exports->data; new < new_exports->data +
134 new_exports->size; new++) {
135 found = 0;
136 if (old_exports != NULL) {
137 for (old = old_exports->data; old < old_exports->data +
138 old_exports->size; old++) {
139 if (strcmp(new->name, old->name) == 0 &&
140 strcmp(new->sect->name, old->sect->name)
141 == 0) {
142 found = 1;
143 break;
147 if (found == 0) {
148 if (last_sect != new->sect) {
149 last_sect = new->sect;
150 printf("\n%s%s", addstr, new->sect->name);
152 printf(" %s", new->name);
157 void foreach_new_section(struct superbfd *oldsbfd, struct superbfd *newsbfd,
158 void (*s_fn)(struct superbfd *, asection *))
160 asection *oldsect, *newsect;
161 struct supersect *old_ss, *new_ss;
162 for (newsect = newsbfd->abfd->sections; newsect != NULL;
163 newsect = newsect->next) {
164 if (starts_with(newsect->name, ".rodata.str") ||
165 is_special(newsect))
166 continue;
167 for (oldsect = oldsbfd->abfd->sections; oldsect != NULL;
168 oldsect = oldsect->next) {
169 if (strcmp(newsect->name, oldsect->name) != 0 &&
170 strcmp(label_lookup(newsbfd, newsect->symbol),
171 label_lookup(oldsbfd, oldsect->symbol))
172 != 0)
173 continue;
174 if (!starts_with(newsect->name, ".rodata"))
175 break;
176 new_ss = fetch_supersect(oldsbfd, oldsect);
177 old_ss = fetch_supersect(oldsbfd, oldsect);
178 if (old_ss->contents.size != new_ss->contents.size ||
179 memcmp(old_ss->contents.data, new_ss->contents.data,
180 old_ss->contents.size) != 0)
181 oldsect = NULL;
182 break;
184 if (oldsect == NULL)
185 s_fn(newsbfd, newsect);
189 void foreach_nonmatching(struct superbfd *oldsbfd, struct superbfd *newsbfd,
190 void (*s_fn)(struct superbfd *, asection *))
192 asection *newp, *oldp;
193 struct supersect *old_ss, *new_ss;
194 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
195 if (!starts_with(newp->name, ".text"))
196 continue;
197 new_ss = fetch_supersect(newsbfd, newp);
198 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
199 if (oldp == NULL)
200 continue;
201 old_ss = fetch_supersect(oldsbfd, oldp);
202 if (new_ss->contents.size == old_ss->contents.size &&
203 memcmp(new_ss->contents.data, old_ss->contents.data,
204 new_ss->contents.size) == 0 &&
205 reloc_cmp(oldsbfd, oldp, newsbfd, newp) == 0)
206 continue;
207 s_fn(newsbfd, newp);
211 static void print_section_symbol_renames(struct superbfd *oldsbfd,
212 struct superbfd *newsbfd)
214 asection *newp, *oldp;
215 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
216 if (!starts_with(newp->name, ".text") &&
217 !starts_with(newp->name, ".data") &&
218 !starts_with(newp->name, ".rodata") &&
219 !starts_with(newp->name, ".bss"))
220 continue;
221 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
222 if (oldp == NULL)
223 continue;
225 const char *old_label = label_lookup(oldsbfd, oldp->symbol);
226 const char *new_label = label_lookup(newsbfd, newp->symbol);
228 if (strcmp(old_label, new_label) == 0)
229 continue;
230 printf("%s %s;", new_label, old_label);
232 printf("\n");
236 * reloc_cmp checks to see whether the old section and the new section
237 * reference different read-only data in their relocations -- if a hard-coded
238 * string has been changed between the old file and the new file, reloc_cmp
239 * will detect the difference.
241 int reloc_cmp(struct superbfd *oldsbfd, asection *oldp,
242 struct superbfd *newsbfd, asection *newp)
244 int i;
245 struct supersect *old_ss, *new_ss;
247 old_ss = fetch_supersect(oldsbfd, oldp);
248 new_ss = fetch_supersect(newsbfd, newp);
250 if (old_ss->relocs.size != new_ss->relocs.size)
251 return -1;
253 for (i = 0; i < old_ss->relocs.size; i++) {
254 struct supersect *ro_old_ss, *ro_new_ss;
256 asymbol *old_sym = *old_ss->relocs.data[i]->sym_ptr_ptr;
257 asymbol *new_sym = *new_ss->relocs.data[i]->sym_ptr_ptr;
259 ro_old_ss = fetch_supersect(oldsbfd, old_sym->section);
260 ro_new_ss = fetch_supersect(newsbfd, new_sym->section);
262 bfd_vma old_offset =
263 get_reloc_offset(old_ss, old_ss->relocs.data[i], 1);
264 bfd_vma new_offset =
265 get_reloc_offset(new_ss, new_ss->relocs.data[i], 1);
267 if (strcmp(ro_old_ss->name, ro_new_ss->name) != 0)
268 return -1;
270 if (!starts_with(ro_old_ss->name, ".rodata")) {
271 /* for non-rodata, we just compare that the two
272 relocations are to the same offset within the same
273 section. */
274 if (old_sym->value + old_offset !=
275 new_sym->value + new_offset)
276 return -1;
277 continue;
280 if (starts_with(ro_old_ss->name, ".rodata.str") &&
281 /* check it's not an out-of-range relocation to a string;
282 we'll just compare entire sections for them */
283 !(old_offset >= ro_old_ss->contents.size ||
284 new_offset >= ro_new_ss->contents.size)) {
285 if (strcmp
286 (ro_old_ss->contents.data + old_sym->value +
287 old_offset,
288 ro_new_ss->contents.data + new_sym->value +
289 new_offset) != 0)
290 return -1;
291 continue;
294 if (ro_old_ss->contents.size != ro_new_ss->contents.size)
295 return -1;
297 if (memcmp(ro_old_ss->contents.data, ro_new_ss->contents.data,
298 ro_old_ss->contents.size) != 0)
299 return -1;
302 return 0;
305 void print_newbfd_section_name(struct superbfd *sbfd, asection *sect)
307 printf("%s ", sect->name);
310 void print_newbfd_symbol_label(struct superbfd *sbfd, asection *sect)
312 printf("%s ", label_lookup(sbfd, sect->symbol));