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
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
);
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
,
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
[])
56 bfd
*oldbfd
= bfd_openr(argv
[1], NULL
);
57 assert(oldbfd
!= NULL
);
58 bfd
*newbfd
= bfd_openr(argv
[2], NULL
);
59 assert(newbfd
!= NULL
);
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
);
70 foreach_nonmatching(oldsbfd
, newsbfd
, print_newbfd_entry_symbols
);
72 compare_symbols(oldsbfd
, newsbfd
, ~0);
74 compare_symbols(newsbfd
, oldsbfd
, BSF_FUNCTION
);
75 compare_exported_symbols(oldsbfd
, newsbfd
, "");
76 compare_exported_symbols(newsbfd
, oldsbfd
, "del_");
79 assert(bfd_close(oldbfd
));
80 assert(bfd_close(newbfd
));
84 struct export_vec
*get_export_syms(struct superbfd
*sbfd
)
87 struct export_vec
*exports
;
88 exports
= malloc(sizeof(*exports
));
89 assert(exports
!= NULL
);
92 for (sect
= sbfd
->abfd
->sections
; sect
!= NULL
; sect
= sect
->next
) {
93 if (!starts_with(sect
->name
, "__ksymtab") ||
94 ends_with(sect
->name
, "_strings"))
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
;
103 struct export
*exp
= vec_grow(exports
, 1);
105 read_string(ss
, (const char *const *)&sym
->name
);
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
)
119 old_exports
= get_export_syms(oldsbfd
);
120 struct export
*old
, *new;
122 asection
*last_sect
= NULL
;
123 for (new = new_exports
->data
; new < new_exports
->data
+
124 new_exports
->size
; new++) {
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
)
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
);
143 printf(" %s", new->name
);
147 void compare_symbols(struct superbfd
*oldsbfd
, struct superbfd
*newsbfd
,
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)
158 tmp
= symbol_hash_lookup(&old_hash
, (*old
)->name
, TRUE
);
160 fprintf(stderr
, "Two global symbols named %s!\n",
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)
171 tmp
= symbol_hash_lookup(&old_hash
, (*new)->name
, FALSE
);
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"))
186 new_ss
= fetch_supersect(newsbfd
, newp
);
187 oldp
= bfd_get_section_by_name(oldsbfd
->abfd
, newp
->name
);
189 if (s_fn
== print_newbfd_section_name
)
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)
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
)
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
)
221 for (i
= 0; i
< old_ss
->relocs
.size
; i
++) {
222 struct supersect
*ro_old_ss
, *ro_new_ss
;
225 (*old_ss
->relocs
.data
[i
]->sym_ptr_ptr
)->section
;
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"))
235 if (strcmp(ro_old_ss
->name
, ro_new_ss
->name
) != 0)
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")) {
247 (ro_old_ss
->contents
.data
+ old_offset
,
248 ro_new_ss
->contents
.data
+ new_offset
) != 0)
253 if (ro_old_ss
->contents
.size
!= ro_new_ss
->contents
.size
)
256 if (memcmp(ro_old_ss
->contents
.data
, ro_new_ss
->contents
.data
,
257 ro_old_ss
->contents
.size
) != 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
;
273 for (symp
= new_syms
.data
; symp
< new_syms
.data
+ new_syms
.size
;
275 asymbol
*sym
= *symp
;
276 struct supersect
*sym_ss
= fetch_supersect(ss
->parent
,
278 if (sym_ss
!= ss
|| sym
->name
[0] == '\0' ||
279 starts_with(sym
->name
, ".text"))
281 if (sym
->value
!= 0) {
283 "Symbol %s [%x] has nonzero value %lx\n",
284 sym
->name
, sym
->flags
, sym
->value
);
287 printf("%s ", sym
->name
);