xref: /aosp_15_r20/external/elfutils/src/elfcmp.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Compare relevant content of two ELF files.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker    Written by Ulrich Drepper <[email protected]>, 2005.
5*7304104dSAndroid Build Coastguard Worker 
6*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker    it under the terms of the GNU General Public License as published by
8*7304104dSAndroid Build Coastguard Worker    the Free Software Foundation; either version 3 of the License, or
9*7304104dSAndroid Build Coastguard Worker    (at your option) any later version.
10*7304104dSAndroid Build Coastguard Worker 
11*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
12*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
13*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*7304104dSAndroid Build Coastguard Worker    GNU General Public License for more details.
15*7304104dSAndroid Build Coastguard Worker 
16*7304104dSAndroid Build Coastguard Worker    You should have received a copy of the GNU General Public License
17*7304104dSAndroid Build Coastguard Worker    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18*7304104dSAndroid Build Coastguard Worker 
19*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
20*7304104dSAndroid Build Coastguard Worker # include <config.h>
21*7304104dSAndroid Build Coastguard Worker #endif
22*7304104dSAndroid Build Coastguard Worker 
23*7304104dSAndroid Build Coastguard Worker #include <argp.h>
24*7304104dSAndroid Build Coastguard Worker #include <assert.h>
25*7304104dSAndroid Build Coastguard Worker #include <errno.h>
26*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
27*7304104dSAndroid Build Coastguard Worker #include <locale.h>
28*7304104dSAndroid Build Coastguard Worker #include <stdbool.h>
29*7304104dSAndroid Build Coastguard Worker #include <stdio.h>
30*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
31*7304104dSAndroid Build Coastguard Worker #include <string.h>
32*7304104dSAndroid Build Coastguard Worker #include <unistd.h>
33*7304104dSAndroid Build Coastguard Worker 
34*7304104dSAndroid Build Coastguard Worker #include <printversion.h>
35*7304104dSAndroid Build Coastguard Worker #include "../libelf/elf-knowledge.h"
36*7304104dSAndroid Build Coastguard Worker #include "../libebl/libeblP.h"
37*7304104dSAndroid Build Coastguard Worker #include "system.h"
38*7304104dSAndroid Build Coastguard Worker 
39*7304104dSAndroid Build Coastguard Worker /* Prototypes of local functions.  */
40*7304104dSAndroid Build Coastguard Worker static Elf *open_file (const char *fname, int *fdp, Ebl **eblp);
41*7304104dSAndroid Build Coastguard Worker static bool search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx);
42*7304104dSAndroid Build Coastguard Worker static  int regioncompare (const void *p1, const void *p2);
43*7304104dSAndroid Build Coastguard Worker 
44*7304104dSAndroid Build Coastguard Worker 
45*7304104dSAndroid Build Coastguard Worker /* Name and version of program.  */
46*7304104dSAndroid Build Coastguard Worker ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
47*7304104dSAndroid Build Coastguard Worker 
48*7304104dSAndroid Build Coastguard Worker /* Bug report address.  */
49*7304104dSAndroid Build Coastguard Worker ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
50*7304104dSAndroid Build Coastguard Worker 
51*7304104dSAndroid Build Coastguard Worker /* Values for the parameters which have no short form.  */
52*7304104dSAndroid Build Coastguard Worker #define OPT_GAPS		0x100
53*7304104dSAndroid Build Coastguard Worker #define OPT_HASH_INEXACT	0x101
54*7304104dSAndroid Build Coastguard Worker #define OPT_IGNORE_BUILD_ID	0x102
55*7304104dSAndroid Build Coastguard Worker 
56*7304104dSAndroid Build Coastguard Worker /* Definitions of arguments for argp functions.  */
57*7304104dSAndroid Build Coastguard Worker static const struct argp_option options[] =
58*7304104dSAndroid Build Coastguard Worker {
59*7304104dSAndroid Build Coastguard Worker   { NULL, 0, NULL, 0, N_("Control options:"), 0 },
60*7304104dSAndroid Build Coastguard Worker   { "verbose", 'l', NULL, 0,
61*7304104dSAndroid Build Coastguard Worker     N_("Output all differences, not just the first"), 0 },
62*7304104dSAndroid Build Coastguard Worker   { "gaps", OPT_GAPS, "ACTION", 0, N_("Control treatment of gaps in loadable segments [ignore|match] (default: ignore)"), 0 },
63*7304104dSAndroid Build Coastguard Worker   { "hash-inexact", OPT_HASH_INEXACT, NULL, 0,
64*7304104dSAndroid Build Coastguard Worker     N_("Ignore permutation of buckets in SHT_HASH section"), 0 },
65*7304104dSAndroid Build Coastguard Worker   { "ignore-build-id", OPT_IGNORE_BUILD_ID, NULL, 0,
66*7304104dSAndroid Build Coastguard Worker     N_("Ignore differences in build ID"), 0 },
67*7304104dSAndroid Build Coastguard Worker   { "quiet", 'q', NULL, 0, N_("Output nothing; yield exit status only"), 0 },
68*7304104dSAndroid Build Coastguard Worker 
69*7304104dSAndroid Build Coastguard Worker   { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
70*7304104dSAndroid Build Coastguard Worker   { NULL, 0, NULL, 0, NULL, 0 }
71*7304104dSAndroid Build Coastguard Worker };
72*7304104dSAndroid Build Coastguard Worker 
73*7304104dSAndroid Build Coastguard Worker /* Short description of program.  */
74*7304104dSAndroid Build Coastguard Worker static const char doc[] = N_("\
75*7304104dSAndroid Build Coastguard Worker Compare relevant parts of two ELF files for equality.");
76*7304104dSAndroid Build Coastguard Worker 
77*7304104dSAndroid Build Coastguard Worker /* Strings for arguments in help texts.  */
78*7304104dSAndroid Build Coastguard Worker static const char args_doc[] = N_("FILE1 FILE2");
79*7304104dSAndroid Build Coastguard Worker 
80*7304104dSAndroid Build Coastguard Worker /* Prototype for option handler.  */
81*7304104dSAndroid Build Coastguard Worker static error_t parse_opt (int key, char *arg, struct argp_state *state);
82*7304104dSAndroid Build Coastguard Worker 
83*7304104dSAndroid Build Coastguard Worker /* Data structure to communicate with argp functions.  */
84*7304104dSAndroid Build Coastguard Worker static struct argp argp =
85*7304104dSAndroid Build Coastguard Worker {
86*7304104dSAndroid Build Coastguard Worker   options, parse_opt, args_doc, doc, NULL, NULL, NULL
87*7304104dSAndroid Build Coastguard Worker };
88*7304104dSAndroid Build Coastguard Worker 
89*7304104dSAndroid Build Coastguard Worker 
90*7304104dSAndroid Build Coastguard Worker /* How to treat gaps in loadable segments.  */
91*7304104dSAndroid Build Coastguard Worker static enum
92*7304104dSAndroid Build Coastguard Worker   {
93*7304104dSAndroid Build Coastguard Worker     gaps_ignore = 0,
94*7304104dSAndroid Build Coastguard Worker     gaps_match
95*7304104dSAndroid Build Coastguard Worker   }
96*7304104dSAndroid Build Coastguard Worker   gaps;
97*7304104dSAndroid Build Coastguard Worker 
98*7304104dSAndroid Build Coastguard Worker /* Structure to hold information about used regions.  */
99*7304104dSAndroid Build Coastguard Worker struct region
100*7304104dSAndroid Build Coastguard Worker {
101*7304104dSAndroid Build Coastguard Worker   GElf_Addr from;
102*7304104dSAndroid Build Coastguard Worker   GElf_Addr to;
103*7304104dSAndroid Build Coastguard Worker   struct region *next;
104*7304104dSAndroid Build Coastguard Worker };
105*7304104dSAndroid Build Coastguard Worker 
106*7304104dSAndroid Build Coastguard Worker /* Nonzero if only exit status is wanted.  */
107*7304104dSAndroid Build Coastguard Worker static bool quiet;
108*7304104dSAndroid Build Coastguard Worker 
109*7304104dSAndroid Build Coastguard Worker /* True iff multiple differences should be output.  */
110*7304104dSAndroid Build Coastguard Worker static bool verbose;
111*7304104dSAndroid Build Coastguard Worker 
112*7304104dSAndroid Build Coastguard Worker /* True iff SHT_HASH treatment should be generous.  */
113*7304104dSAndroid Build Coastguard Worker static bool hash_inexact;
114*7304104dSAndroid Build Coastguard Worker 
115*7304104dSAndroid Build Coastguard Worker /* True iff build ID notes should be ignored.  */
116*7304104dSAndroid Build Coastguard Worker static bool ignore_build_id;
117*7304104dSAndroid Build Coastguard Worker 
118*7304104dSAndroid Build Coastguard Worker static bool hash_content_equivalent (size_t entsize, Elf_Data *, Elf_Data *);
119*7304104dSAndroid Build Coastguard Worker 
120*7304104dSAndroid Build Coastguard Worker 
121*7304104dSAndroid Build Coastguard Worker int
main(int argc,char * argv[])122*7304104dSAndroid Build Coastguard Worker main (int argc, char *argv[])
123*7304104dSAndroid Build Coastguard Worker {
124*7304104dSAndroid Build Coastguard Worker   /* Set locale.  */
125*7304104dSAndroid Build Coastguard Worker   (void) setlocale (LC_ALL, "");
126*7304104dSAndroid Build Coastguard Worker 
127*7304104dSAndroid Build Coastguard Worker   /* Make sure the message catalog can be found.  */
128*7304104dSAndroid Build Coastguard Worker   (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
129*7304104dSAndroid Build Coastguard Worker 
130*7304104dSAndroid Build Coastguard Worker   /* Initialize the message catalog.  */
131*7304104dSAndroid Build Coastguard Worker   (void) textdomain (PACKAGE_TARNAME);
132*7304104dSAndroid Build Coastguard Worker 
133*7304104dSAndroid Build Coastguard Worker   /* Parse and process arguments.  */
134*7304104dSAndroid Build Coastguard Worker   int remaining;
135*7304104dSAndroid Build Coastguard Worker   (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
136*7304104dSAndroid Build Coastguard Worker 
137*7304104dSAndroid Build Coastguard Worker   /* We expect exactly two non-option parameters.  */
138*7304104dSAndroid Build Coastguard Worker   if (unlikely (remaining + 2 != argc))
139*7304104dSAndroid Build Coastguard Worker     {
140*7304104dSAndroid Build Coastguard Worker       fputs (_("Invalid number of parameters.\n"), stderr);
141*7304104dSAndroid Build Coastguard Worker       argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
142*7304104dSAndroid Build Coastguard Worker       exit (1);
143*7304104dSAndroid Build Coastguard Worker     }
144*7304104dSAndroid Build Coastguard Worker 
145*7304104dSAndroid Build Coastguard Worker   if (quiet)
146*7304104dSAndroid Build Coastguard Worker     verbose = false;
147*7304104dSAndroid Build Coastguard Worker 
148*7304104dSAndroid Build Coastguard Worker   /* Comparing the files is done in two phases:
149*7304104dSAndroid Build Coastguard Worker      1. compare all sections.  Sections which are irrelevant (i.e., if
150*7304104dSAndroid Build Coastguard Worker 	strip would remove them) are ignored.  Some section types are
151*7304104dSAndroid Build Coastguard Worker 	handled special.
152*7304104dSAndroid Build Coastguard Worker      2. all parts of the loadable segments which are not parts of any
153*7304104dSAndroid Build Coastguard Worker 	section is compared according to the rules of the --gaps option.
154*7304104dSAndroid Build Coastguard Worker   */
155*7304104dSAndroid Build Coastguard Worker   int result = 0;
156*7304104dSAndroid Build Coastguard Worker   elf_version (EV_CURRENT);
157*7304104dSAndroid Build Coastguard Worker 
158*7304104dSAndroid Build Coastguard Worker   const char *const fname1 = argv[remaining];
159*7304104dSAndroid Build Coastguard Worker   int fd1;
160*7304104dSAndroid Build Coastguard Worker   Ebl *ebl1;
161*7304104dSAndroid Build Coastguard Worker   Elf *elf1 = open_file (fname1, &fd1, &ebl1);
162*7304104dSAndroid Build Coastguard Worker 
163*7304104dSAndroid Build Coastguard Worker   const char *const fname2 = argv[remaining + 1];
164*7304104dSAndroid Build Coastguard Worker   int fd2;
165*7304104dSAndroid Build Coastguard Worker   Ebl *ebl2;
166*7304104dSAndroid Build Coastguard Worker   Elf *elf2 = open_file (fname2, &fd2, &ebl2);
167*7304104dSAndroid Build Coastguard Worker 
168*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr ehdr1_mem;
169*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr *ehdr1 = gelf_getehdr (elf1, &ehdr1_mem);
170*7304104dSAndroid Build Coastguard Worker   if (ehdr1 == NULL)
171*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get ELF header of '%s': %s"),
172*7304104dSAndroid Build Coastguard Worker 	   fname1, elf_errmsg (-1));
173*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr ehdr2_mem;
174*7304104dSAndroid Build Coastguard Worker   GElf_Ehdr *ehdr2 = gelf_getehdr (elf2, &ehdr2_mem);
175*7304104dSAndroid Build Coastguard Worker   if (ehdr2 == NULL)
176*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get ELF header of '%s': %s"),
177*7304104dSAndroid Build Coastguard Worker 	   fname2, elf_errmsg (-1));
178*7304104dSAndroid Build Coastguard Worker 
179*7304104dSAndroid Build Coastguard Worker #define DIFFERENCE							      \
180*7304104dSAndroid Build Coastguard Worker   do									      \
181*7304104dSAndroid Build Coastguard Worker     {									      \
182*7304104dSAndroid Build Coastguard Worker       result = 1;							      \
183*7304104dSAndroid Build Coastguard Worker       if (! verbose)							      \
184*7304104dSAndroid Build Coastguard Worker 	goto out;							      \
185*7304104dSAndroid Build Coastguard Worker     }									      \
186*7304104dSAndroid Build Coastguard Worker   while (0)
187*7304104dSAndroid Build Coastguard Worker 
188*7304104dSAndroid Build Coastguard Worker   /* Compare the ELF headers.  */
189*7304104dSAndroid Build Coastguard Worker   if (unlikely (memcmp (ehdr1->e_ident, ehdr2->e_ident, EI_NIDENT) != 0
190*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_type != ehdr2->e_type
191*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_machine != ehdr2->e_machine
192*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_version != ehdr2->e_version
193*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_entry != ehdr2->e_entry
194*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_phoff != ehdr2->e_phoff
195*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_flags != ehdr2->e_flags
196*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_ehsize != ehdr2->e_ehsize
197*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_phentsize != ehdr2->e_phentsize
198*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_phnum != ehdr2->e_phnum
199*7304104dSAndroid Build Coastguard Worker 		|| ehdr1->e_shentsize != ehdr2->e_shentsize))
200*7304104dSAndroid Build Coastguard Worker     {
201*7304104dSAndroid Build Coastguard Worker       if (! quiet)
202*7304104dSAndroid Build Coastguard Worker 	error (0, 0, _("%s %s diff: ELF header"), fname1, fname2);
203*7304104dSAndroid Build Coastguard Worker       DIFFERENCE;
204*7304104dSAndroid Build Coastguard Worker     }
205*7304104dSAndroid Build Coastguard Worker 
206*7304104dSAndroid Build Coastguard Worker   size_t shnum1;
207*7304104dSAndroid Build Coastguard Worker   size_t shnum2;
208*7304104dSAndroid Build Coastguard Worker   if (unlikely (elf_getshdrnum (elf1, &shnum1) != 0))
209*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get section count of '%s': %s"),
210*7304104dSAndroid Build Coastguard Worker 	   fname1, elf_errmsg (-1));
211*7304104dSAndroid Build Coastguard Worker   if (unlikely (elf_getshdrnum (elf2, &shnum2) != 0))
212*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get section count of '%s': %s"),
213*7304104dSAndroid Build Coastguard Worker 	   fname2, elf_errmsg (-1));
214*7304104dSAndroid Build Coastguard Worker   if (unlikely (shnum1 != shnum2))
215*7304104dSAndroid Build Coastguard Worker     {
216*7304104dSAndroid Build Coastguard Worker       if (! quiet)
217*7304104dSAndroid Build Coastguard Worker 	error (0, 0, _("%s %s diff: section count"), fname1, fname2);
218*7304104dSAndroid Build Coastguard Worker       DIFFERENCE;
219*7304104dSAndroid Build Coastguard Worker     }
220*7304104dSAndroid Build Coastguard Worker 
221*7304104dSAndroid Build Coastguard Worker   size_t phnum1;
222*7304104dSAndroid Build Coastguard Worker   size_t phnum2;
223*7304104dSAndroid Build Coastguard Worker   if (unlikely (elf_getphdrnum (elf1, &phnum1) != 0))
224*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get program header count of '%s': %s"),
225*7304104dSAndroid Build Coastguard Worker 	   fname1, elf_errmsg (-1));
226*7304104dSAndroid Build Coastguard Worker   if (unlikely (elf_getphdrnum (elf2, &phnum2) != 0))
227*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get program header count of '%s': %s"),
228*7304104dSAndroid Build Coastguard Worker 	   fname2, elf_errmsg (-1));
229*7304104dSAndroid Build Coastguard Worker   if (unlikely (phnum1 != phnum2))
230*7304104dSAndroid Build Coastguard Worker     {
231*7304104dSAndroid Build Coastguard Worker       if (! quiet)
232*7304104dSAndroid Build Coastguard Worker 	error (0, 0, _("%s %s diff: program header count"),
233*7304104dSAndroid Build Coastguard Worker 	       fname1, fname2);
234*7304104dSAndroid Build Coastguard Worker       DIFFERENCE;
235*7304104dSAndroid Build Coastguard Worker     }
236*7304104dSAndroid Build Coastguard Worker 
237*7304104dSAndroid Build Coastguard Worker   size_t shstrndx1;
238*7304104dSAndroid Build Coastguard Worker   size_t shstrndx2;
239*7304104dSAndroid Build Coastguard Worker   if (elf_getshdrstrndx (elf1, &shstrndx1) != 0)
240*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get hdrstrndx of '%s': %s"),
241*7304104dSAndroid Build Coastguard Worker 	   fname1, elf_errmsg (-1));
242*7304104dSAndroid Build Coastguard Worker   if (elf_getshdrstrndx (elf2, &shstrndx2) != 0)
243*7304104dSAndroid Build Coastguard Worker     error (2, 0, _("cannot get hdrstrndx of '%s': %s"),
244*7304104dSAndroid Build Coastguard Worker 	   fname2, elf_errmsg (-1));
245*7304104dSAndroid Build Coastguard Worker   if (shstrndx1 != shstrndx2)
246*7304104dSAndroid Build Coastguard Worker     {
247*7304104dSAndroid Build Coastguard Worker       if (! quiet)
248*7304104dSAndroid Build Coastguard Worker 	error (0, 0, _("%s %s diff: shdr string index"),
249*7304104dSAndroid Build Coastguard Worker 	       fname1, fname2);
250*7304104dSAndroid Build Coastguard Worker       DIFFERENCE;
251*7304104dSAndroid Build Coastguard Worker     }
252*7304104dSAndroid Build Coastguard Worker 
253*7304104dSAndroid Build Coastguard Worker   /* Iterate over all sections.  We expect the sections in the two
254*7304104dSAndroid Build Coastguard Worker      files to match exactly.  */
255*7304104dSAndroid Build Coastguard Worker   Elf_Scn *scn1 = NULL;
256*7304104dSAndroid Build Coastguard Worker   Elf_Scn *scn2 = NULL;
257*7304104dSAndroid Build Coastguard Worker   struct region *regions = NULL;
258*7304104dSAndroid Build Coastguard Worker   size_t nregions = 0;
259*7304104dSAndroid Build Coastguard Worker   while (1)
260*7304104dSAndroid Build Coastguard Worker     {
261*7304104dSAndroid Build Coastguard Worker       GElf_Shdr shdr1_mem;
262*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *shdr1;
263*7304104dSAndroid Build Coastguard Worker       const char *sname1 = NULL;
264*7304104dSAndroid Build Coastguard Worker       do
265*7304104dSAndroid Build Coastguard Worker 	{
266*7304104dSAndroid Build Coastguard Worker 	  scn1 = elf_nextscn (elf1, scn1);
267*7304104dSAndroid Build Coastguard Worker 	  shdr1 = gelf_getshdr (scn1, &shdr1_mem);
268*7304104dSAndroid Build Coastguard Worker 	  if (shdr1 != NULL)
269*7304104dSAndroid Build Coastguard Worker 	    sname1 = elf_strptr (elf1, shstrndx1, shdr1->sh_name);
270*7304104dSAndroid Build Coastguard Worker 	}
271*7304104dSAndroid Build Coastguard Worker       while (scn1 != NULL && shdr1 != NULL
272*7304104dSAndroid Build Coastguard Worker 	     && ebl_section_strip_p (ebl1, shdr1, sname1, true, false));
273*7304104dSAndroid Build Coastguard Worker 
274*7304104dSAndroid Build Coastguard Worker       GElf_Shdr shdr2_mem;
275*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *shdr2;
276*7304104dSAndroid Build Coastguard Worker       const char *sname2 = NULL;
277*7304104dSAndroid Build Coastguard Worker       do
278*7304104dSAndroid Build Coastguard Worker 	{
279*7304104dSAndroid Build Coastguard Worker 	  scn2 = elf_nextscn (elf2, scn2);
280*7304104dSAndroid Build Coastguard Worker 	  shdr2 = gelf_getshdr (scn2, &shdr2_mem);
281*7304104dSAndroid Build Coastguard Worker 	  if (shdr2 != NULL)
282*7304104dSAndroid Build Coastguard Worker 	    sname2 = elf_strptr (elf2, shstrndx2, shdr2->sh_name);
283*7304104dSAndroid Build Coastguard Worker 	}
284*7304104dSAndroid Build Coastguard Worker       while (scn2 != NULL && shdr2 != NULL
285*7304104dSAndroid Build Coastguard Worker 	     && ebl_section_strip_p (ebl2, shdr2, sname2, true, false));
286*7304104dSAndroid Build Coastguard Worker 
287*7304104dSAndroid Build Coastguard Worker       if (scn1 == NULL || scn2 == NULL || shdr1 == NULL || shdr2 == NULL)
288*7304104dSAndroid Build Coastguard Worker 	break;
289*7304104dSAndroid Build Coastguard Worker 
290*7304104dSAndroid Build Coastguard Worker       if (gaps != gaps_ignore && (shdr1->sh_flags & SHF_ALLOC) != 0)
291*7304104dSAndroid Build Coastguard Worker 	{
292*7304104dSAndroid Build Coastguard Worker 	  struct region *newp = (struct region *) alloca (sizeof (*newp));
293*7304104dSAndroid Build Coastguard Worker 	  newp->from = shdr1->sh_offset;
294*7304104dSAndroid Build Coastguard Worker 	  newp->to = shdr1->sh_offset + shdr1->sh_size;
295*7304104dSAndroid Build Coastguard Worker 	  newp->next = regions;
296*7304104dSAndroid Build Coastguard Worker 	  regions = newp;
297*7304104dSAndroid Build Coastguard Worker 
298*7304104dSAndroid Build Coastguard Worker 	  ++nregions;
299*7304104dSAndroid Build Coastguard Worker 	}
300*7304104dSAndroid Build Coastguard Worker 
301*7304104dSAndroid Build Coastguard Worker       /* Compare the headers.  We allow the name to be at a different
302*7304104dSAndroid Build Coastguard Worker 	 location.  */
303*7304104dSAndroid Build Coastguard Worker       if (unlikely (sname1 == NULL || sname2 == NULL
304*7304104dSAndroid Build Coastguard Worker 		    || strcmp (sname1, sname2) != 0))
305*7304104dSAndroid Build Coastguard Worker 	{
306*7304104dSAndroid Build Coastguard Worker 	  error (0, 0, _("%s %s differ: section [%zu], [%zu] name"),
307*7304104dSAndroid Build Coastguard Worker 		 fname1, fname2, elf_ndxscn (scn1), elf_ndxscn (scn2));
308*7304104dSAndroid Build Coastguard Worker 	  DIFFERENCE;
309*7304104dSAndroid Build Coastguard Worker 	}
310*7304104dSAndroid Build Coastguard Worker 
311*7304104dSAndroid Build Coastguard Worker       /* We ignore certain sections.  */
312*7304104dSAndroid Build Coastguard Worker       if ((sname1 != NULL && strcmp (sname1, ".gnu_debuglink") == 0)
313*7304104dSAndroid Build Coastguard Worker 	  || (sname1 != NULL && strcmp (sname1, ".gnu.prelink_undo") == 0))
314*7304104dSAndroid Build Coastguard Worker 	continue;
315*7304104dSAndroid Build Coastguard Worker 
316*7304104dSAndroid Build Coastguard Worker       if (shdr1->sh_type != shdr2->sh_type
317*7304104dSAndroid Build Coastguard Worker 	  // XXX Any flags which should be ignored?
318*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_flags != shdr2->sh_flags
319*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_addr != shdr2->sh_addr
320*7304104dSAndroid Build Coastguard Worker 	  || (shdr1->sh_offset != shdr2->sh_offset
321*7304104dSAndroid Build Coastguard Worker 	      && (shdr1->sh_flags & SHF_ALLOC)
322*7304104dSAndroid Build Coastguard Worker 	      && ehdr1->e_type != ET_REL)
323*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_size != shdr2->sh_size
324*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_link != shdr2->sh_link
325*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_info != shdr2->sh_info
326*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_addralign != shdr2->sh_addralign
327*7304104dSAndroid Build Coastguard Worker 	  || shdr1->sh_entsize != shdr2->sh_entsize)
328*7304104dSAndroid Build Coastguard Worker 	{
329*7304104dSAndroid Build Coastguard Worker 	  error (0, 0, _("%s %s differ: section [%zu] '%s' header"),
330*7304104dSAndroid Build Coastguard Worker 		 fname1, fname2, elf_ndxscn (scn1), sname1);
331*7304104dSAndroid Build Coastguard Worker 	  DIFFERENCE;
332*7304104dSAndroid Build Coastguard Worker 	}
333*7304104dSAndroid Build Coastguard Worker 
334*7304104dSAndroid Build Coastguard Worker       Elf_Data *data1 = elf_getdata (scn1, NULL);
335*7304104dSAndroid Build Coastguard Worker       if (data1 == NULL)
336*7304104dSAndroid Build Coastguard Worker 	error (2, 0,
337*7304104dSAndroid Build Coastguard Worker 	       _("cannot get content of section %zu in '%s': %s"),
338*7304104dSAndroid Build Coastguard Worker 	       elf_ndxscn (scn1), fname1, elf_errmsg (-1));
339*7304104dSAndroid Build Coastguard Worker 
340*7304104dSAndroid Build Coastguard Worker       Elf_Data *data2 = elf_getdata (scn2, NULL);
341*7304104dSAndroid Build Coastguard Worker       if (data2 == NULL)
342*7304104dSAndroid Build Coastguard Worker 	error (2, 0,
343*7304104dSAndroid Build Coastguard Worker 	       _("cannot get content of section %zu in '%s': %s"),
344*7304104dSAndroid Build Coastguard Worker 	       elf_ndxscn (scn2), fname2, elf_errmsg (-1));
345*7304104dSAndroid Build Coastguard Worker 
346*7304104dSAndroid Build Coastguard Worker       switch (shdr1->sh_type)
347*7304104dSAndroid Build Coastguard Worker 	{
348*7304104dSAndroid Build Coastguard Worker 	case SHT_DYNSYM:
349*7304104dSAndroid Build Coastguard Worker 	case SHT_SYMTAB:
350*7304104dSAndroid Build Coastguard Worker 	  if (shdr1->sh_entsize == 0)
351*7304104dSAndroid Build Coastguard Worker 	    error (2, 0,
352*7304104dSAndroid Build Coastguard Worker 		   _("symbol table [%zu] in '%s' has zero sh_entsize"),
353*7304104dSAndroid Build Coastguard Worker 		   elf_ndxscn (scn1), fname1);
354*7304104dSAndroid Build Coastguard Worker 
355*7304104dSAndroid Build Coastguard Worker 	  /* Iterate over the symbol table.  We ignore the st_size
356*7304104dSAndroid Build Coastguard Worker 	     value of undefined symbols.  */
357*7304104dSAndroid Build Coastguard Worker 	  for (int ndx = 0; ndx < (int) (shdr1->sh_size / shdr1->sh_entsize);
358*7304104dSAndroid Build Coastguard Worker 	       ++ndx)
359*7304104dSAndroid Build Coastguard Worker 	    {
360*7304104dSAndroid Build Coastguard Worker 	      GElf_Sym sym1_mem;
361*7304104dSAndroid Build Coastguard Worker 	      GElf_Sym *sym1 = gelf_getsym (data1, ndx, &sym1_mem);
362*7304104dSAndroid Build Coastguard Worker 	      if (sym1 == NULL)
363*7304104dSAndroid Build Coastguard Worker 		error (2, 0,
364*7304104dSAndroid Build Coastguard Worker 		       _("cannot get symbol in '%s': %s"),
365*7304104dSAndroid Build Coastguard Worker 		       fname1, elf_errmsg (-1));
366*7304104dSAndroid Build Coastguard Worker 	      GElf_Sym sym2_mem;
367*7304104dSAndroid Build Coastguard Worker 	      GElf_Sym *sym2 = gelf_getsym (data2, ndx, &sym2_mem);
368*7304104dSAndroid Build Coastguard Worker 	      if (sym2 == NULL)
369*7304104dSAndroid Build Coastguard Worker 		error (2, 0,
370*7304104dSAndroid Build Coastguard Worker 		       _("cannot get symbol in '%s': %s"),
371*7304104dSAndroid Build Coastguard Worker 		       fname2, elf_errmsg (-1));
372*7304104dSAndroid Build Coastguard Worker 
373*7304104dSAndroid Build Coastguard Worker 	      const char *name1 = elf_strptr (elf1, shdr1->sh_link,
374*7304104dSAndroid Build Coastguard Worker 					      sym1->st_name);
375*7304104dSAndroid Build Coastguard Worker 	      const char *name2 = elf_strptr (elf2, shdr2->sh_link,
376*7304104dSAndroid Build Coastguard Worker 					      sym2->st_name);
377*7304104dSAndroid Build Coastguard Worker 	      if (unlikely (name1 == NULL || name2 == NULL
378*7304104dSAndroid Build Coastguard Worker 			    || strcmp (name1, name2) != 0
379*7304104dSAndroid Build Coastguard Worker 			    || sym1->st_value != sym2->st_value
380*7304104dSAndroid Build Coastguard Worker 			    || (sym1->st_size != sym2->st_size
381*7304104dSAndroid Build Coastguard Worker 				&& sym1->st_shndx != SHN_UNDEF)
382*7304104dSAndroid Build Coastguard Worker 			    || sym1->st_info != sym2->st_info
383*7304104dSAndroid Build Coastguard Worker 			    || sym1->st_other != sym2->st_other
384*7304104dSAndroid Build Coastguard Worker 			    || sym1->st_shndx != sym2->st_shndx))
385*7304104dSAndroid Build Coastguard Worker 		{
386*7304104dSAndroid Build Coastguard Worker 		  // XXX Do we want to allow reordered symbol tables?
387*7304104dSAndroid Build Coastguard Worker 		symtab_mismatch:
388*7304104dSAndroid Build Coastguard Worker 		  if (! quiet)
389*7304104dSAndroid Build Coastguard Worker 		    {
390*7304104dSAndroid Build Coastguard Worker 		      if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
391*7304104dSAndroid Build Coastguard Worker 			error (0, 0,
392*7304104dSAndroid Build Coastguard Worker 			       _("%s %s differ: symbol table [%zu]"),
393*7304104dSAndroid Build Coastguard Worker 			       fname1, fname2, elf_ndxscn (scn1));
394*7304104dSAndroid Build Coastguard Worker 		      else
395*7304104dSAndroid Build Coastguard Worker 			error (0, 0, _("\
396*7304104dSAndroid Build Coastguard Worker %s %s differ: symbol table [%zu,%zu]"),
397*7304104dSAndroid Build Coastguard Worker 			       fname1, fname2, elf_ndxscn (scn1),
398*7304104dSAndroid Build Coastguard Worker 			       elf_ndxscn (scn2));
399*7304104dSAndroid Build Coastguard Worker 		    }
400*7304104dSAndroid Build Coastguard Worker 		  DIFFERENCE;
401*7304104dSAndroid Build Coastguard Worker 		  break;
402*7304104dSAndroid Build Coastguard Worker 		}
403*7304104dSAndroid Build Coastguard Worker 
404*7304104dSAndroid Build Coastguard Worker 	      if (sym1->st_shndx == SHN_UNDEF
405*7304104dSAndroid Build Coastguard Worker 		  && sym1->st_size != sym2->st_size)
406*7304104dSAndroid Build Coastguard Worker 		{
407*7304104dSAndroid Build Coastguard Worker 		  /* The size of the symbol in the object defining it
408*7304104dSAndroid Build Coastguard Worker 		     might have changed.  That is OK unless the symbol
409*7304104dSAndroid Build Coastguard Worker 		     is used in a copy relocation.  Look over the
410*7304104dSAndroid Build Coastguard Worker 		     sections in both files and determine which
411*7304104dSAndroid Build Coastguard Worker 		     relocation section uses this symbol table
412*7304104dSAndroid Build Coastguard Worker 		     section.  Then look through the relocations to
413*7304104dSAndroid Build Coastguard Worker 		     see whether any copy relocation references this
414*7304104dSAndroid Build Coastguard Worker 		     symbol.  */
415*7304104dSAndroid Build Coastguard Worker 		  if (search_for_copy_reloc (ebl1, elf_ndxscn (scn1), ndx)
416*7304104dSAndroid Build Coastguard Worker 		      || search_for_copy_reloc (ebl2, elf_ndxscn (scn2), ndx))
417*7304104dSAndroid Build Coastguard Worker 		    goto symtab_mismatch;
418*7304104dSAndroid Build Coastguard Worker 		}
419*7304104dSAndroid Build Coastguard Worker 	    }
420*7304104dSAndroid Build Coastguard Worker 	  break;
421*7304104dSAndroid Build Coastguard Worker 
422*7304104dSAndroid Build Coastguard Worker 	case SHT_NOTE:
423*7304104dSAndroid Build Coastguard Worker 	  /* Parse the note format and compare the notes themselves.  */
424*7304104dSAndroid Build Coastguard Worker 	  {
425*7304104dSAndroid Build Coastguard Worker 	    GElf_Nhdr note1;
426*7304104dSAndroid Build Coastguard Worker 	    GElf_Nhdr note2;
427*7304104dSAndroid Build Coastguard Worker 
428*7304104dSAndroid Build Coastguard Worker 	    size_t off1 = 0;
429*7304104dSAndroid Build Coastguard Worker 	    size_t off2 = 0;
430*7304104dSAndroid Build Coastguard Worker 	    size_t name_offset;
431*7304104dSAndroid Build Coastguard Worker 	    size_t desc_offset;
432*7304104dSAndroid Build Coastguard Worker 	    while (off1 < data1->d_size
433*7304104dSAndroid Build Coastguard Worker 		   && (off1 = gelf_getnote (data1, off1, &note1,
434*7304104dSAndroid Build Coastguard Worker 					    &name_offset, &desc_offset)) > 0)
435*7304104dSAndroid Build Coastguard Worker 	      {
436*7304104dSAndroid Build Coastguard Worker 		const char *name1 = (note1.n_namesz == 0
437*7304104dSAndroid Build Coastguard Worker 				     ? "" : data1->d_buf + name_offset);
438*7304104dSAndroid Build Coastguard Worker 		const void *desc1 = data1->d_buf + desc_offset;
439*7304104dSAndroid Build Coastguard Worker 		if (off2 >= data2->d_size)
440*7304104dSAndroid Build Coastguard Worker 		  {
441*7304104dSAndroid Build Coastguard Worker 		    if (! quiet)
442*7304104dSAndroid Build Coastguard Worker 		      error (0, 0, _("\
443*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu] '%s' number of notes"),
444*7304104dSAndroid Build Coastguard Worker 			     fname1, fname2, elf_ndxscn (scn1), sname1);
445*7304104dSAndroid Build Coastguard Worker 		    DIFFERENCE;
446*7304104dSAndroid Build Coastguard Worker 		  }
447*7304104dSAndroid Build Coastguard Worker 		off2 = gelf_getnote (data2, off2, &note2,
448*7304104dSAndroid Build Coastguard Worker 				     &name_offset, &desc_offset);
449*7304104dSAndroid Build Coastguard Worker 		if (off2 == 0)
450*7304104dSAndroid Build Coastguard Worker 		  error (2, 0, _("\
451*7304104dSAndroid Build Coastguard Worker cannot read note section [%zu] '%s' in '%s': %s"),
452*7304104dSAndroid Build Coastguard Worker 			 elf_ndxscn (scn2), sname2, fname2, elf_errmsg (-1));
453*7304104dSAndroid Build Coastguard Worker 		const char *name2 = (note2.n_namesz == 0
454*7304104dSAndroid Build Coastguard Worker 				     ? "" : data2->d_buf + name_offset);
455*7304104dSAndroid Build Coastguard Worker 		const void *desc2 = data2->d_buf + desc_offset;
456*7304104dSAndroid Build Coastguard Worker 
457*7304104dSAndroid Build Coastguard Worker 		if (note1.n_namesz != note2.n_namesz
458*7304104dSAndroid Build Coastguard Worker 		    || memcmp (name1, name2, note1.n_namesz))
459*7304104dSAndroid Build Coastguard Worker 		  {
460*7304104dSAndroid Build Coastguard Worker 		    if (! quiet)
461*7304104dSAndroid Build Coastguard Worker 		      error (0, 0, _("\
462*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu] '%s' note name"),
463*7304104dSAndroid Build Coastguard Worker 			     fname1, fname2, elf_ndxscn (scn1), sname1);
464*7304104dSAndroid Build Coastguard Worker 		    DIFFERENCE;
465*7304104dSAndroid Build Coastguard Worker 		  }
466*7304104dSAndroid Build Coastguard Worker 		if (note1.n_type != note2.n_type)
467*7304104dSAndroid Build Coastguard Worker 		  {
468*7304104dSAndroid Build Coastguard Worker 		    if (! quiet)
469*7304104dSAndroid Build Coastguard Worker 		      error (0, 0, _("\
470*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu] '%s' note '%s' type"),
471*7304104dSAndroid Build Coastguard Worker 			     fname1, fname2, elf_ndxscn (scn1), sname1, name1);
472*7304104dSAndroid Build Coastguard Worker 		    DIFFERENCE;
473*7304104dSAndroid Build Coastguard Worker 		  }
474*7304104dSAndroid Build Coastguard Worker 		if (note1.n_descsz != note2.n_descsz
475*7304104dSAndroid Build Coastguard Worker 		    || memcmp (desc1, desc2, note1.n_descsz))
476*7304104dSAndroid Build Coastguard Worker 		  {
477*7304104dSAndroid Build Coastguard Worker 		    if (note1.n_type == NT_GNU_BUILD_ID
478*7304104dSAndroid Build Coastguard Worker 			&& note1.n_namesz == sizeof "GNU"
479*7304104dSAndroid Build Coastguard Worker 			&& !memcmp (name1, "GNU", sizeof "GNU"))
480*7304104dSAndroid Build Coastguard Worker 		      {
481*7304104dSAndroid Build Coastguard Worker 			if (note1.n_descsz != note2.n_descsz)
482*7304104dSAndroid Build Coastguard Worker 			  {
483*7304104dSAndroid Build Coastguard Worker 			    if (! quiet)
484*7304104dSAndroid Build Coastguard Worker 			      error (0, 0, _("\
485*7304104dSAndroid Build Coastguard Worker %s %s differ: build ID length"),
486*7304104dSAndroid Build Coastguard Worker 				     fname1, fname2);
487*7304104dSAndroid Build Coastguard Worker 			    DIFFERENCE;
488*7304104dSAndroid Build Coastguard Worker 			  }
489*7304104dSAndroid Build Coastguard Worker 			else if (! ignore_build_id)
490*7304104dSAndroid Build Coastguard Worker 			  {
491*7304104dSAndroid Build Coastguard Worker 			    if (! quiet)
492*7304104dSAndroid Build Coastguard Worker 			      error (0, 0, _("\
493*7304104dSAndroid Build Coastguard Worker %s %s differ: build ID content"),
494*7304104dSAndroid Build Coastguard Worker 				     fname1, fname2);
495*7304104dSAndroid Build Coastguard Worker 			    DIFFERENCE;
496*7304104dSAndroid Build Coastguard Worker 			  }
497*7304104dSAndroid Build Coastguard Worker 		      }
498*7304104dSAndroid Build Coastguard Worker 		    else
499*7304104dSAndroid Build Coastguard Worker 		      {
500*7304104dSAndroid Build Coastguard Worker 			if (! quiet)
501*7304104dSAndroid Build Coastguard Worker 			  error (0, 0, _("\
502*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu] '%s' note '%s' content"),
503*7304104dSAndroid Build Coastguard Worker 				 fname1, fname2, elf_ndxscn (scn1), sname1,
504*7304104dSAndroid Build Coastguard Worker 				 name1);
505*7304104dSAndroid Build Coastguard Worker 			DIFFERENCE;
506*7304104dSAndroid Build Coastguard Worker 		      }
507*7304104dSAndroid Build Coastguard Worker 		  }
508*7304104dSAndroid Build Coastguard Worker 	      }
509*7304104dSAndroid Build Coastguard Worker 	    if (off2 < data2->d_size)
510*7304104dSAndroid Build Coastguard Worker 	      {
511*7304104dSAndroid Build Coastguard Worker 		if (! quiet)
512*7304104dSAndroid Build Coastguard Worker 		  error (0, 0, _("\
513*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu] '%s' number of notes"),
514*7304104dSAndroid Build Coastguard Worker 			 fname1, fname2, elf_ndxscn (scn1), sname1);
515*7304104dSAndroid Build Coastguard Worker 		DIFFERENCE;
516*7304104dSAndroid Build Coastguard Worker 	      }
517*7304104dSAndroid Build Coastguard Worker 	  }
518*7304104dSAndroid Build Coastguard Worker 	  break;
519*7304104dSAndroid Build Coastguard Worker 
520*7304104dSAndroid Build Coastguard Worker 	default:
521*7304104dSAndroid Build Coastguard Worker 	  /* Compare the section content byte for byte.  */
522*7304104dSAndroid Build Coastguard Worker 	  assert (shdr1->sh_type == SHT_NOBITS
523*7304104dSAndroid Build Coastguard Worker 		  || (data1->d_buf != NULL || data1->d_size == 0));
524*7304104dSAndroid Build Coastguard Worker 	  assert (shdr2->sh_type == SHT_NOBITS
525*7304104dSAndroid Build Coastguard Worker 		  || (data2->d_buf != NULL || data1->d_size == 0));
526*7304104dSAndroid Build Coastguard Worker 
527*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (data1->d_size != data2->d_size
528*7304104dSAndroid Build Coastguard Worker 			|| (shdr1->sh_type != SHT_NOBITS
529*7304104dSAndroid Build Coastguard Worker 			    && data1->d_size != 0
530*7304104dSAndroid Build Coastguard Worker 			    && memcmp (data1->d_buf, data2->d_buf,
531*7304104dSAndroid Build Coastguard Worker 				       data1->d_size) != 0)))
532*7304104dSAndroid Build Coastguard Worker 	    {
533*7304104dSAndroid Build Coastguard Worker 	      if (hash_inexact
534*7304104dSAndroid Build Coastguard Worker 		  && shdr1->sh_type == SHT_HASH
535*7304104dSAndroid Build Coastguard Worker 		  && data1->d_size == data2->d_size
536*7304104dSAndroid Build Coastguard Worker 		  && hash_content_equivalent (shdr1->sh_entsize, data1, data2))
537*7304104dSAndroid Build Coastguard Worker 		break;
538*7304104dSAndroid Build Coastguard Worker 
539*7304104dSAndroid Build Coastguard Worker 	      if (! quiet)
540*7304104dSAndroid Build Coastguard Worker 		{
541*7304104dSAndroid Build Coastguard Worker 		  if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
542*7304104dSAndroid Build Coastguard Worker 		    error (0, 0, _("\
543*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu] '%s' content"),
544*7304104dSAndroid Build Coastguard Worker 			   fname1, fname2, elf_ndxscn (scn1), sname1);
545*7304104dSAndroid Build Coastguard Worker 		  else
546*7304104dSAndroid Build Coastguard Worker 		    error (0, 0, _("\
547*7304104dSAndroid Build Coastguard Worker %s %s differ: section [%zu,%zu] '%s' content"),
548*7304104dSAndroid Build Coastguard Worker 			   fname1, fname2, elf_ndxscn (scn1),
549*7304104dSAndroid Build Coastguard Worker 			   elf_ndxscn (scn2), sname1);
550*7304104dSAndroid Build Coastguard Worker 		}
551*7304104dSAndroid Build Coastguard Worker 	      DIFFERENCE;
552*7304104dSAndroid Build Coastguard Worker 	    }
553*7304104dSAndroid Build Coastguard Worker 	  break;
554*7304104dSAndroid Build Coastguard Worker 	}
555*7304104dSAndroid Build Coastguard Worker     }
556*7304104dSAndroid Build Coastguard Worker 
557*7304104dSAndroid Build Coastguard Worker   if (unlikely (scn1 != scn2))
558*7304104dSAndroid Build Coastguard Worker     {
559*7304104dSAndroid Build Coastguard Worker       if (! quiet)
560*7304104dSAndroid Build Coastguard Worker 	error (0, 0,
561*7304104dSAndroid Build Coastguard Worker 	       _("%s %s differ: unequal amount of important sections"),
562*7304104dSAndroid Build Coastguard Worker 	       fname1, fname2);
563*7304104dSAndroid Build Coastguard Worker       DIFFERENCE;
564*7304104dSAndroid Build Coastguard Worker     }
565*7304104dSAndroid Build Coastguard Worker 
566*7304104dSAndroid Build Coastguard Worker   /* We we look at gaps, create artificial ones for the parts of the
567*7304104dSAndroid Build Coastguard Worker      program which we are not in sections.  */
568*7304104dSAndroid Build Coastguard Worker   struct region ehdr_region;
569*7304104dSAndroid Build Coastguard Worker   struct region phdr_region;
570*7304104dSAndroid Build Coastguard Worker   if (gaps != gaps_ignore)
571*7304104dSAndroid Build Coastguard Worker     {
572*7304104dSAndroid Build Coastguard Worker       ehdr_region.from = 0;
573*7304104dSAndroid Build Coastguard Worker       ehdr_region.to = ehdr1->e_ehsize;
574*7304104dSAndroid Build Coastguard Worker       ehdr_region.next = &phdr_region;
575*7304104dSAndroid Build Coastguard Worker 
576*7304104dSAndroid Build Coastguard Worker       phdr_region.from = ehdr1->e_phoff;
577*7304104dSAndroid Build Coastguard Worker       phdr_region.to = ehdr1->e_phoff + phnum1 * ehdr1->e_phentsize;
578*7304104dSAndroid Build Coastguard Worker       phdr_region.next = regions;
579*7304104dSAndroid Build Coastguard Worker 
580*7304104dSAndroid Build Coastguard Worker       regions = &ehdr_region;
581*7304104dSAndroid Build Coastguard Worker       nregions += 2;
582*7304104dSAndroid Build Coastguard Worker     }
583*7304104dSAndroid Build Coastguard Worker 
584*7304104dSAndroid Build Coastguard Worker   /* If we need to look at the gaps we need access to the file data.  */
585*7304104dSAndroid Build Coastguard Worker   char *raw1 = NULL;
586*7304104dSAndroid Build Coastguard Worker   size_t size1 = 0;
587*7304104dSAndroid Build Coastguard Worker   char *raw2 = NULL;
588*7304104dSAndroid Build Coastguard Worker   size_t size2 = 0;
589*7304104dSAndroid Build Coastguard Worker   struct region *regionsarr = alloca (nregions * sizeof (struct region));
590*7304104dSAndroid Build Coastguard Worker   if (gaps != gaps_ignore)
591*7304104dSAndroid Build Coastguard Worker     {
592*7304104dSAndroid Build Coastguard Worker       raw1 = elf_rawfile (elf1, &size1);
593*7304104dSAndroid Build Coastguard Worker       if (raw1 == NULL )
594*7304104dSAndroid Build Coastguard Worker 	error (2, 0, _("cannot load data of '%s': %s"),
595*7304104dSAndroid Build Coastguard Worker 	       fname1, elf_errmsg (-1));
596*7304104dSAndroid Build Coastguard Worker 
597*7304104dSAndroid Build Coastguard Worker       raw2 = elf_rawfile (elf2, &size2);
598*7304104dSAndroid Build Coastguard Worker       if (raw2 == NULL )
599*7304104dSAndroid Build Coastguard Worker 	error (2, 0, _("cannot load data of '%s': %s"),
600*7304104dSAndroid Build Coastguard Worker 	       fname2, elf_errmsg (-1));
601*7304104dSAndroid Build Coastguard Worker 
602*7304104dSAndroid Build Coastguard Worker       for (size_t cnt = 0; cnt < nregions; ++cnt)
603*7304104dSAndroid Build Coastguard Worker 	{
604*7304104dSAndroid Build Coastguard Worker 	  regionsarr[cnt] = *regions;
605*7304104dSAndroid Build Coastguard Worker 	  regions = regions->next;
606*7304104dSAndroid Build Coastguard Worker 	}
607*7304104dSAndroid Build Coastguard Worker 
608*7304104dSAndroid Build Coastguard Worker       qsort (regionsarr, nregions, sizeof (regionsarr[0]), regioncompare);
609*7304104dSAndroid Build Coastguard Worker     }
610*7304104dSAndroid Build Coastguard Worker 
611*7304104dSAndroid Build Coastguard Worker   /* Compare the program header tables.  */
612*7304104dSAndroid Build Coastguard Worker   for (unsigned int ndx = 0; ndx < phnum1; ++ndx)
613*7304104dSAndroid Build Coastguard Worker     {
614*7304104dSAndroid Build Coastguard Worker       GElf_Phdr phdr1_mem;
615*7304104dSAndroid Build Coastguard Worker       GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem);
616*7304104dSAndroid Build Coastguard Worker       if (phdr1 == NULL)
617*7304104dSAndroid Build Coastguard Worker 	error (2, 0,
618*7304104dSAndroid Build Coastguard Worker 	       _("cannot get program header entry %d of '%s': %s"),
619*7304104dSAndroid Build Coastguard Worker 	       ndx, fname1, elf_errmsg (-1));
620*7304104dSAndroid Build Coastguard Worker       GElf_Phdr phdr2_mem;
621*7304104dSAndroid Build Coastguard Worker       GElf_Phdr *phdr2 = gelf_getphdr (elf2, ndx, &phdr2_mem);
622*7304104dSAndroid Build Coastguard Worker       if (phdr2 == NULL)
623*7304104dSAndroid Build Coastguard Worker 	error (2, 0,
624*7304104dSAndroid Build Coastguard Worker 	       _("cannot get program header entry %d of '%s': %s"),
625*7304104dSAndroid Build Coastguard Worker 	       ndx, fname2, elf_errmsg (-1));
626*7304104dSAndroid Build Coastguard Worker 
627*7304104dSAndroid Build Coastguard Worker       if (unlikely (memcmp (phdr1, phdr2, sizeof (GElf_Phdr)) != 0))
628*7304104dSAndroid Build Coastguard Worker 	{
629*7304104dSAndroid Build Coastguard Worker 	  if (! quiet)
630*7304104dSAndroid Build Coastguard Worker 	    error (0, 0, _("%s %s differ: program header %d"),
631*7304104dSAndroid Build Coastguard Worker 		   fname1, fname2, ndx);
632*7304104dSAndroid Build Coastguard Worker 	  DIFFERENCE;
633*7304104dSAndroid Build Coastguard Worker 	}
634*7304104dSAndroid Build Coastguard Worker 
635*7304104dSAndroid Build Coastguard Worker       if (gaps != gaps_ignore && phdr1->p_type == PT_LOAD)
636*7304104dSAndroid Build Coastguard Worker 	{
637*7304104dSAndroid Build Coastguard Worker 	  size_t cnt = 0;
638*7304104dSAndroid Build Coastguard Worker 	  while (cnt < nregions && regionsarr[cnt].to < phdr1->p_offset)
639*7304104dSAndroid Build Coastguard Worker 	    ++cnt;
640*7304104dSAndroid Build Coastguard Worker 
641*7304104dSAndroid Build Coastguard Worker 	  GElf_Off last = phdr1->p_offset;
642*7304104dSAndroid Build Coastguard Worker 	  GElf_Off end = phdr1->p_offset + phdr1->p_filesz;
643*7304104dSAndroid Build Coastguard Worker 	  while (cnt < nregions && regionsarr[cnt].from < end)
644*7304104dSAndroid Build Coastguard Worker 	    {
645*7304104dSAndroid Build Coastguard Worker 	      if (last < regionsarr[cnt].from)
646*7304104dSAndroid Build Coastguard Worker 		{
647*7304104dSAndroid Build Coastguard Worker 		  /* Compare the [LAST,FROM) region.  */
648*7304104dSAndroid Build Coastguard Worker 		  assert (gaps == gaps_match);
649*7304104dSAndroid Build Coastguard Worker 		  if (unlikely (memcmp (raw1 + last, raw2 + last,
650*7304104dSAndroid Build Coastguard Worker 					regionsarr[cnt].from - last) != 0))
651*7304104dSAndroid Build Coastguard Worker 		    {
652*7304104dSAndroid Build Coastguard Worker 		    gapmismatch:
653*7304104dSAndroid Build Coastguard Worker 		      if (!quiet)
654*7304104dSAndroid Build Coastguard Worker 			error (0, 0, _("%s %s differ: gap"),
655*7304104dSAndroid Build Coastguard Worker 			       fname1, fname2);
656*7304104dSAndroid Build Coastguard Worker 		      DIFFERENCE;
657*7304104dSAndroid Build Coastguard Worker 		      break;
658*7304104dSAndroid Build Coastguard Worker 		    }
659*7304104dSAndroid Build Coastguard Worker 
660*7304104dSAndroid Build Coastguard Worker 		}
661*7304104dSAndroid Build Coastguard Worker 	      last = regionsarr[cnt].to;
662*7304104dSAndroid Build Coastguard Worker 	      ++cnt;
663*7304104dSAndroid Build Coastguard Worker 	    }
664*7304104dSAndroid Build Coastguard Worker 
665*7304104dSAndroid Build Coastguard Worker 	  if (cnt == nregions && last < end)
666*7304104dSAndroid Build Coastguard Worker 	    goto gapmismatch;
667*7304104dSAndroid Build Coastguard Worker 	}
668*7304104dSAndroid Build Coastguard Worker     }
669*7304104dSAndroid Build Coastguard Worker 
670*7304104dSAndroid Build Coastguard Worker  out:
671*7304104dSAndroid Build Coastguard Worker   elf_end (elf1);
672*7304104dSAndroid Build Coastguard Worker   elf_end (elf2);
673*7304104dSAndroid Build Coastguard Worker   ebl_closebackend (ebl1);
674*7304104dSAndroid Build Coastguard Worker   ebl_closebackend (ebl2);
675*7304104dSAndroid Build Coastguard Worker   close (fd1);
676*7304104dSAndroid Build Coastguard Worker   close (fd2);
677*7304104dSAndroid Build Coastguard Worker 
678*7304104dSAndroid Build Coastguard Worker   return result;
679*7304104dSAndroid Build Coastguard Worker }
680*7304104dSAndroid Build Coastguard Worker 
681*7304104dSAndroid Build Coastguard Worker 
682*7304104dSAndroid Build Coastguard Worker /* Handle program arguments.  */
683*7304104dSAndroid Build Coastguard Worker static error_t
parse_opt(int key,char * arg,struct argp_state * state)684*7304104dSAndroid Build Coastguard Worker parse_opt (int key, char *arg,
685*7304104dSAndroid Build Coastguard Worker 	   struct argp_state *state __attribute__ ((unused)))
686*7304104dSAndroid Build Coastguard Worker {
687*7304104dSAndroid Build Coastguard Worker   switch (key)
688*7304104dSAndroid Build Coastguard Worker     {
689*7304104dSAndroid Build Coastguard Worker     case 'q':
690*7304104dSAndroid Build Coastguard Worker       quiet = true;
691*7304104dSAndroid Build Coastguard Worker       break;
692*7304104dSAndroid Build Coastguard Worker 
693*7304104dSAndroid Build Coastguard Worker     case 'l':
694*7304104dSAndroid Build Coastguard Worker       verbose = true;
695*7304104dSAndroid Build Coastguard Worker       break;
696*7304104dSAndroid Build Coastguard Worker 
697*7304104dSAndroid Build Coastguard Worker     case OPT_GAPS:
698*7304104dSAndroid Build Coastguard Worker       if (strcasecmp (arg, "ignore") == 0)
699*7304104dSAndroid Build Coastguard Worker 	gaps = gaps_ignore;
700*7304104dSAndroid Build Coastguard Worker       else if (likely (strcasecmp (arg, "match") == 0))
701*7304104dSAndroid Build Coastguard Worker 	gaps = gaps_match;
702*7304104dSAndroid Build Coastguard Worker       else
703*7304104dSAndroid Build Coastguard Worker 	{
704*7304104dSAndroid Build Coastguard Worker 	  fprintf (stderr,
705*7304104dSAndroid Build Coastguard Worker 		   _("Invalid value '%s' for --gaps parameter."),
706*7304104dSAndroid Build Coastguard Worker 		   arg);
707*7304104dSAndroid Build Coastguard Worker 	  argp_help (&argp, stderr, ARGP_HELP_SEE,
708*7304104dSAndroid Build Coastguard Worker 		     program_invocation_short_name);
709*7304104dSAndroid Build Coastguard Worker 	  exit (1);
710*7304104dSAndroid Build Coastguard Worker 	}
711*7304104dSAndroid Build Coastguard Worker       break;
712*7304104dSAndroid Build Coastguard Worker 
713*7304104dSAndroid Build Coastguard Worker     case OPT_HASH_INEXACT:
714*7304104dSAndroid Build Coastguard Worker       hash_inexact = true;
715*7304104dSAndroid Build Coastguard Worker       break;
716*7304104dSAndroid Build Coastguard Worker 
717*7304104dSAndroid Build Coastguard Worker     case OPT_IGNORE_BUILD_ID:
718*7304104dSAndroid Build Coastguard Worker       ignore_build_id = true;
719*7304104dSAndroid Build Coastguard Worker       break;
720*7304104dSAndroid Build Coastguard Worker 
721*7304104dSAndroid Build Coastguard Worker     default:
722*7304104dSAndroid Build Coastguard Worker       return ARGP_ERR_UNKNOWN;
723*7304104dSAndroid Build Coastguard Worker     }
724*7304104dSAndroid Build Coastguard Worker   return 0;
725*7304104dSAndroid Build Coastguard Worker }
726*7304104dSAndroid Build Coastguard Worker 
727*7304104dSAndroid Build Coastguard Worker 
728*7304104dSAndroid Build Coastguard Worker static Elf *
open_file(const char * fname,int * fdp,Ebl ** eblp)729*7304104dSAndroid Build Coastguard Worker open_file (const char *fname, int *fdp, Ebl **eblp)
730*7304104dSAndroid Build Coastguard Worker {
731*7304104dSAndroid Build Coastguard Worker   int fd = open (fname, O_RDONLY);
732*7304104dSAndroid Build Coastguard Worker   if (unlikely (fd == -1))
733*7304104dSAndroid Build Coastguard Worker     error (2, errno, _("cannot open '%s'"), fname);
734*7304104dSAndroid Build Coastguard Worker   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
735*7304104dSAndroid Build Coastguard Worker   if (elf == NULL)
736*7304104dSAndroid Build Coastguard Worker     error (2, 0,
737*7304104dSAndroid Build Coastguard Worker 	   _("cannot create ELF descriptor for '%s': %s"),
738*7304104dSAndroid Build Coastguard Worker 	   fname, elf_errmsg (-1));
739*7304104dSAndroid Build Coastguard Worker   Ebl *ebl = ebl_openbackend (elf);
740*7304104dSAndroid Build Coastguard Worker   if (ebl == NULL)
741*7304104dSAndroid Build Coastguard Worker     error (2, 0,
742*7304104dSAndroid Build Coastguard Worker 	   _("cannot create EBL descriptor for '%s'"), fname);
743*7304104dSAndroid Build Coastguard Worker 
744*7304104dSAndroid Build Coastguard Worker   *fdp = fd;
745*7304104dSAndroid Build Coastguard Worker   *eblp = ebl;
746*7304104dSAndroid Build Coastguard Worker   return elf;
747*7304104dSAndroid Build Coastguard Worker }
748*7304104dSAndroid Build Coastguard Worker 
749*7304104dSAndroid Build Coastguard Worker 
750*7304104dSAndroid Build Coastguard Worker static bool
search_for_copy_reloc(Ebl * ebl,size_t scnndx,int symndx)751*7304104dSAndroid Build Coastguard Worker search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx)
752*7304104dSAndroid Build Coastguard Worker {
753*7304104dSAndroid Build Coastguard Worker   Elf_Scn *scn = NULL;
754*7304104dSAndroid Build Coastguard Worker   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
755*7304104dSAndroid Build Coastguard Worker     {
756*7304104dSAndroid Build Coastguard Worker       GElf_Shdr shdr_mem;
757*7304104dSAndroid Build Coastguard Worker       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
758*7304104dSAndroid Build Coastguard Worker       if (shdr == NULL)
759*7304104dSAndroid Build Coastguard Worker 	error (2, 0,
760*7304104dSAndroid Build Coastguard Worker 	       _("cannot get section header of section %zu: %s"),
761*7304104dSAndroid Build Coastguard Worker 	       elf_ndxscn (scn), elf_errmsg (-1));
762*7304104dSAndroid Build Coastguard Worker 
763*7304104dSAndroid Build Coastguard Worker       if ((shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
764*7304104dSAndroid Build Coastguard Worker 	  || shdr->sh_link != scnndx)
765*7304104dSAndroid Build Coastguard Worker 	continue;
766*7304104dSAndroid Build Coastguard Worker 
767*7304104dSAndroid Build Coastguard Worker       Elf_Data *data = elf_getdata (scn, NULL);
768*7304104dSAndroid Build Coastguard Worker       if (data == NULL)
769*7304104dSAndroid Build Coastguard Worker 	error (2, 0,
770*7304104dSAndroid Build Coastguard Worker 	       _("cannot get content of section %zu: %s"),
771*7304104dSAndroid Build Coastguard Worker 	       elf_ndxscn (scn), elf_errmsg (-1));
772*7304104dSAndroid Build Coastguard Worker 
773*7304104dSAndroid Build Coastguard Worker       if (shdr->sh_type == SHT_REL && shdr->sh_entsize != 0)
774*7304104dSAndroid Build Coastguard Worker 	for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
775*7304104dSAndroid Build Coastguard Worker 	     ++ndx)
776*7304104dSAndroid Build Coastguard Worker 	  {
777*7304104dSAndroid Build Coastguard Worker 	    GElf_Rel rel_mem;
778*7304104dSAndroid Build Coastguard Worker 	    GElf_Rel *rel = gelf_getrel (data, ndx, &rel_mem);
779*7304104dSAndroid Build Coastguard Worker 	    if (rel == NULL)
780*7304104dSAndroid Build Coastguard Worker 	      error (2, 0, _("cannot get relocation: %s"),
781*7304104dSAndroid Build Coastguard Worker 		     elf_errmsg (-1));
782*7304104dSAndroid Build Coastguard Worker 
783*7304104dSAndroid Build Coastguard Worker 	    if ((int) GELF_R_SYM (rel->r_info) == symndx
784*7304104dSAndroid Build Coastguard Worker 		&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
785*7304104dSAndroid Build Coastguard Worker 	      return true;
786*7304104dSAndroid Build Coastguard Worker 	  }
787*7304104dSAndroid Build Coastguard Worker       else if (shdr->sh_entsize != 0)
788*7304104dSAndroid Build Coastguard Worker 	for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
789*7304104dSAndroid Build Coastguard Worker 	     ++ndx)
790*7304104dSAndroid Build Coastguard Worker 	  {
791*7304104dSAndroid Build Coastguard Worker 	    GElf_Rela rela_mem;
792*7304104dSAndroid Build Coastguard Worker 	    GElf_Rela *rela = gelf_getrela (data, ndx, &rela_mem);
793*7304104dSAndroid Build Coastguard Worker 	    if (rela == NULL)
794*7304104dSAndroid Build Coastguard Worker 	      error (2, 0, _("cannot get relocation: %s"),
795*7304104dSAndroid Build Coastguard Worker 		     elf_errmsg (-1));
796*7304104dSAndroid Build Coastguard Worker 
797*7304104dSAndroid Build Coastguard Worker 	    if ((int) GELF_R_SYM (rela->r_info) == symndx
798*7304104dSAndroid Build Coastguard Worker 		&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
799*7304104dSAndroid Build Coastguard Worker 	      return true;
800*7304104dSAndroid Build Coastguard Worker 	  }
801*7304104dSAndroid Build Coastguard Worker     }
802*7304104dSAndroid Build Coastguard Worker 
803*7304104dSAndroid Build Coastguard Worker   return false;
804*7304104dSAndroid Build Coastguard Worker }
805*7304104dSAndroid Build Coastguard Worker 
806*7304104dSAndroid Build Coastguard Worker 
807*7304104dSAndroid Build Coastguard Worker static int
regioncompare(const void * p1,const void * p2)808*7304104dSAndroid Build Coastguard Worker regioncompare (const void *p1, const void *p2)
809*7304104dSAndroid Build Coastguard Worker {
810*7304104dSAndroid Build Coastguard Worker   const struct region *r1 = (const struct region *) p1;
811*7304104dSAndroid Build Coastguard Worker   const struct region *r2 = (const struct region *) p2;
812*7304104dSAndroid Build Coastguard Worker 
813*7304104dSAndroid Build Coastguard Worker   if (r1->from < r2->from)
814*7304104dSAndroid Build Coastguard Worker     return -1;
815*7304104dSAndroid Build Coastguard Worker   return 1;
816*7304104dSAndroid Build Coastguard Worker }
817*7304104dSAndroid Build Coastguard Worker 
818*7304104dSAndroid Build Coastguard Worker 
819*7304104dSAndroid Build Coastguard Worker static int
compare_Elf32_Word(const void * p1,const void * p2)820*7304104dSAndroid Build Coastguard Worker compare_Elf32_Word (const void *p1, const void *p2)
821*7304104dSAndroid Build Coastguard Worker {
822*7304104dSAndroid Build Coastguard Worker   const Elf32_Word *w1 = p1;
823*7304104dSAndroid Build Coastguard Worker   const Elf32_Word *w2 = p2;
824*7304104dSAndroid Build Coastguard Worker   return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
825*7304104dSAndroid Build Coastguard Worker }
826*7304104dSAndroid Build Coastguard Worker 
827*7304104dSAndroid Build Coastguard Worker static int
compare_Elf64_Xword(const void * p1,const void * p2)828*7304104dSAndroid Build Coastguard Worker compare_Elf64_Xword (const void *p1, const void *p2)
829*7304104dSAndroid Build Coastguard Worker {
830*7304104dSAndroid Build Coastguard Worker   const Elf64_Xword *w1 = p1;
831*7304104dSAndroid Build Coastguard Worker   const Elf64_Xword *w2 = p2;
832*7304104dSAndroid Build Coastguard Worker   return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
833*7304104dSAndroid Build Coastguard Worker }
834*7304104dSAndroid Build Coastguard Worker 
835*7304104dSAndroid Build Coastguard Worker static bool
hash_content_equivalent(size_t entsize,Elf_Data * data1,Elf_Data * data2)836*7304104dSAndroid Build Coastguard Worker hash_content_equivalent (size_t entsize, Elf_Data *data1, Elf_Data *data2)
837*7304104dSAndroid Build Coastguard Worker {
838*7304104dSAndroid Build Coastguard Worker #define CHECK_HASH(Hash_Word)						      \
839*7304104dSAndroid Build Coastguard Worker   {									      \
840*7304104dSAndroid Build Coastguard Worker     const Hash_Word *const hash1 = data1->d_buf;			      \
841*7304104dSAndroid Build Coastguard Worker     const Hash_Word *const hash2 = data2->d_buf;			      \
842*7304104dSAndroid Build Coastguard Worker     const size_t nbucket = hash1[0];					      \
843*7304104dSAndroid Build Coastguard Worker     const size_t nchain = hash1[1];					      \
844*7304104dSAndroid Build Coastguard Worker     if (data1->d_size != (2 + nbucket + nchain) * sizeof hash1[0]	      \
845*7304104dSAndroid Build Coastguard Worker 	|| hash2[0] != nbucket || hash2[1] != nchain)			      \
846*7304104dSAndroid Build Coastguard Worker       return false;							      \
847*7304104dSAndroid Build Coastguard Worker 									      \
848*7304104dSAndroid Build Coastguard Worker     const Hash_Word *const bucket1 = &hash1[2];				      \
849*7304104dSAndroid Build Coastguard Worker     const Hash_Word *const chain1 = &bucket1[nbucket];			      \
850*7304104dSAndroid Build Coastguard Worker     const Hash_Word *const bucket2 = &hash2[2];				      \
851*7304104dSAndroid Build Coastguard Worker     const Hash_Word *const chain2 = &bucket2[nbucket];			      \
852*7304104dSAndroid Build Coastguard Worker 									      \
853*7304104dSAndroid Build Coastguard Worker     bool chain_ok[nchain];						      \
854*7304104dSAndroid Build Coastguard Worker     Hash_Word temp1[nchain - 1];					      \
855*7304104dSAndroid Build Coastguard Worker     Hash_Word temp2[nchain - 1];					      \
856*7304104dSAndroid Build Coastguard Worker     memset (chain_ok, 0, sizeof chain_ok);				      \
857*7304104dSAndroid Build Coastguard Worker     for (size_t i = 0; i < nbucket; ++i)				      \
858*7304104dSAndroid Build Coastguard Worker       {									      \
859*7304104dSAndroid Build Coastguard Worker 	if (bucket1[i] >= nchain || bucket2[i] >= nchain)		      \
860*7304104dSAndroid Build Coastguard Worker 	  return false;							      \
861*7304104dSAndroid Build Coastguard Worker 									      \
862*7304104dSAndroid Build Coastguard Worker 	size_t b1 = 0;							      \
863*7304104dSAndroid Build Coastguard Worker 	for (size_t p = bucket1[i]; p != STN_UNDEF; p = chain1[p])	      \
864*7304104dSAndroid Build Coastguard Worker 	  if (p >= nchain || b1 >= nchain - 1)				      \
865*7304104dSAndroid Build Coastguard Worker 	    return false;						      \
866*7304104dSAndroid Build Coastguard Worker 	  else								      \
867*7304104dSAndroid Build Coastguard Worker 	    temp1[b1++] = p;						      \
868*7304104dSAndroid Build Coastguard Worker 									      \
869*7304104dSAndroid Build Coastguard Worker 	size_t b2 = 0;							      \
870*7304104dSAndroid Build Coastguard Worker 	for (size_t p = bucket2[i]; p != STN_UNDEF; p = chain2[p])	      \
871*7304104dSAndroid Build Coastguard Worker 	  if (p >= nchain || b2 >= nchain - 1)				      \
872*7304104dSAndroid Build Coastguard Worker 	    return false;						      \
873*7304104dSAndroid Build Coastguard Worker 	  else								      \
874*7304104dSAndroid Build Coastguard Worker 	    temp2[b2++] = p;						      \
875*7304104dSAndroid Build Coastguard Worker 									      \
876*7304104dSAndroid Build Coastguard Worker 	if (b1 != b2)							      \
877*7304104dSAndroid Build Coastguard Worker 	  return false;							      \
878*7304104dSAndroid Build Coastguard Worker 									      \
879*7304104dSAndroid Build Coastguard Worker 	qsort (temp1, b1, sizeof temp1[0], compare_##Hash_Word);	      \
880*7304104dSAndroid Build Coastguard Worker 	qsort (temp2, b2, sizeof temp2[0], compare_##Hash_Word);	      \
881*7304104dSAndroid Build Coastguard Worker 									      \
882*7304104dSAndroid Build Coastguard Worker 	for (b1 = 0; b1 < b2; ++b1)					      \
883*7304104dSAndroid Build Coastguard Worker 	  if (temp1[b1] != temp2[b1])					      \
884*7304104dSAndroid Build Coastguard Worker 	    return false;						      \
885*7304104dSAndroid Build Coastguard Worker 	  else								      \
886*7304104dSAndroid Build Coastguard Worker 	    chain_ok[temp1[b1]] = true;					      \
887*7304104dSAndroid Build Coastguard Worker       }									      \
888*7304104dSAndroid Build Coastguard Worker 									      \
889*7304104dSAndroid Build Coastguard Worker     for (size_t i = 0; i < nchain; ++i)					      \
890*7304104dSAndroid Build Coastguard Worker       if (!chain_ok[i] && chain1[i] != chain2[i])			      \
891*7304104dSAndroid Build Coastguard Worker 	return false;							      \
892*7304104dSAndroid Build Coastguard Worker 									      \
893*7304104dSAndroid Build Coastguard Worker     return true;							      \
894*7304104dSAndroid Build Coastguard Worker   }
895*7304104dSAndroid Build Coastguard Worker 
896*7304104dSAndroid Build Coastguard Worker   switch (entsize)
897*7304104dSAndroid Build Coastguard Worker     {
898*7304104dSAndroid Build Coastguard Worker     case 4:
899*7304104dSAndroid Build Coastguard Worker       CHECK_HASH (Elf32_Word);
900*7304104dSAndroid Build Coastguard Worker       break;
901*7304104dSAndroid Build Coastguard Worker     case 8:
902*7304104dSAndroid Build Coastguard Worker       CHECK_HASH (Elf64_Xword);
903*7304104dSAndroid Build Coastguard Worker       break;
904*7304104dSAndroid Build Coastguard Worker     }
905*7304104dSAndroid Build Coastguard Worker 
906*7304104dSAndroid Build Coastguard Worker   return false;
907*7304104dSAndroid Build Coastguard Worker }
908*7304104dSAndroid Build Coastguard Worker 
909*7304104dSAndroid Build Coastguard Worker 
910*7304104dSAndroid Build Coastguard Worker #include "debugpred.h"
911