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