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
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
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
);
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
[])
67 bfd
*oldbfd
= bfd_openr(argv
[1], NULL
);
68 assert(oldbfd
!= NULL
);
69 bfd
*newbfd
= bfd_openr(argv
[2], NULL
);
70 assert(newbfd
!= NULL
);
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
);
82 foreach_new_section(oldsbfd
, newsbfd
, print_newbfd_section_name
);
84 foreach_new_section(newsbfd
, oldsbfd
, print_newbfd_symbol_label
);
85 compare_exported_symbols(oldsbfd
, newsbfd
, "");
86 compare_exported_symbols(newsbfd
, oldsbfd
, "del_");
89 assert(bfd_close(oldbfd
));
90 assert(bfd_close(newbfd
));
94 struct export_vec
*get_export_syms(struct superbfd
*sbfd
)
97 struct export_vec
*exports
;
98 exports
= malloc(sizeof(*exports
));
99 assert(exports
!= NULL
);
102 for (sect
= sbfd
->abfd
->sections
; sect
!= NULL
; sect
= sect
->next
) {
103 if (!starts_with(sect
->name
, "__ksymtab") ||
104 ends_with(sect
->name
, "_strings"))
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
;
113 struct export
*exp
= vec_grow(exports
, 1);
115 read_string(ss
, (const char *const *)&sym
->name
);
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
)
129 old_exports
= get_export_syms(oldsbfd
);
130 struct export
*old
, *new;
132 asection
*last_sect
= NULL
;
133 for (new = new_exports
->data
; new < new_exports
->data
+
134 new_exports
->size
; new++) {
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
)
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") ||
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
))
174 if (!starts_with(newsect
->name
, ".rodata"))
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)
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"))
197 new_ss
= fetch_supersect(newsbfd
, newp
);
198 oldp
= bfd_get_section_by_name(oldsbfd
->abfd
, newp
->name
);
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)
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"))
221 oldp
= bfd_get_section_by_name(oldsbfd
->abfd
, newp
->name
);
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)
230 printf("%s %s;", new_label
, old_label
);
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
)
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
)
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
);
263 get_reloc_offset(old_ss
, old_ss
->relocs
.data
[i
], 1);
265 get_reloc_offset(new_ss
, new_ss
->relocs
.data
[i
], 1);
267 if (strcmp(ro_old_ss
->name
, ro_new_ss
->name
) != 0)
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
274 if (old_sym
->value
+ old_offset
!=
275 new_sym
->value
+ new_offset
)
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
)) {
286 (ro_old_ss
->contents
.data
+ old_sym
->value
+
288 ro_new_ss
->contents
.data
+ new_sym
->value
+
294 if (ro_old_ss
->contents
.size
!= ro_new_ss
->contents
.size
)
297 if (memcmp(ro_old_ss
->contents
.data
, ro_new_ss
->contents
.data
,
298 ro_old_ss
->contents
.size
) != 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
));