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