Home | History | Annotate | Download | only in src
      1 /* Compare relevant content of two ELF files.
      2    Copyright (C) 2005-2012, 2014 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Written by Ulrich Drepper <drepper (at) 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.  */
     42 static Elf *open_file (const char *fname, int *fdp, Ebl **eblp);
     43 static bool search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx);
     44 static  int regioncompare (const void *p1, const void *p2);
     45 
     46 
     47 /* Name and version of program.  */
     48 static void print_version (FILE *stream, struct argp_state *state);
     49 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
     50 
     51 /* Bug report address.  */
     52 ARGP_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.  */
     60 static 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.  */
     77 static const char doc[] = N_("\
     78 Compare relevant parts of two ELF files for equality.");
     79 
     80 /* Strings for arguments in help texts.  */
     81 static const char args_doc[] = N_("FILE1 FILE2");
     82 
     83 /* Prototype for option handler.  */
     84 static error_t parse_opt (int key, char *arg, struct argp_state *state);
     85 
     86 /* Data structure to communicate with argp functions.  */
     87 static 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.  */
     94 static enum
     95   {
     96     gaps_ignore = 0,
     97     gaps_match
     98   }
     99   gaps;
    100 
    101 /* Structure to hold information about used regions.  */
    102 struct region
    103 {
    104   GElf_Addr from;
    105   GElf_Addr to;
    106   struct region *next;
    107 };
    108 
    109 /* Nonzero if only exit status is wanted.  */
    110 static bool quiet;
    111 
    112 /* True iff multiple differences should be output.  */
    113 static bool verbose;
    114 
    115 /* True iff SHT_HASH treatment should be generous.  */
    116 static bool hash_inexact;
    117 
    118 /* True iff build ID notes should be ignored.  */
    119 static bool ignore_build_id;
    120 
    121 static bool hash_content_equivalent (size_t entsize, Elf_Data *, Elf_Data *);
    122 
    123 
    124 int
    125 main (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 (strcmp (sname1, sname2) != 0))
    291 	{
    292 	  error (0, 0, gettext ("%s %s differ: section [%zu], [%zu] name"),
    293 		 fname1, fname2, elf_ndxscn (scn1), elf_ndxscn (scn2));
    294 	  DIFFERENCE;
    295 	}
    296 
    297       /* We ignore certain sections.  */
    298       if (strcmp (sname1, ".gnu_debuglink") == 0
    299 	  || strcmp (sname1, ".gnu.prelink_undo") == 0)
    300 	continue;
    301 
    302       if (shdr1->sh_type != shdr2->sh_type
    303 	  // XXX Any flags which should be ignored?
    304 	  || shdr1->sh_flags != shdr2->sh_flags
    305 	  || shdr1->sh_addr != shdr2->sh_addr
    306 	  || (shdr1->sh_offset != shdr2->sh_offset
    307 	      && (shdr1->sh_flags & SHF_ALLOC)
    308 	      && ehdr1->e_type != ET_REL)
    309 	  || shdr1->sh_size != shdr2->sh_size
    310 	  || shdr1->sh_link != shdr2->sh_link
    311 	  || shdr1->sh_info != shdr2->sh_info
    312 	  || shdr1->sh_addralign != shdr2->sh_addralign
    313 	  || shdr1->sh_entsize != shdr2->sh_entsize)
    314 	{
    315 	  error (0, 0, gettext ("%s %s differ: section [%zu] '%s' header"),
    316 		 fname1, fname2, elf_ndxscn (scn1), sname1);
    317 	  DIFFERENCE;
    318 	}
    319 
    320       Elf_Data *data1 = elf_getdata (scn1, NULL);
    321       if (data1 == NULL)
    322 	error (2, 0,
    323 	       gettext ("cannot get content of section %zu in '%s': %s"),
    324 	       elf_ndxscn (scn1), fname1, elf_errmsg (-1));
    325 
    326       Elf_Data *data2 = elf_getdata (scn2, NULL);
    327       if (data2 == NULL)
    328 	error (2, 0,
    329 	       gettext ("cannot get content of section %zu in '%s': %s"),
    330 	       elf_ndxscn (scn2), fname2, elf_errmsg (-1));
    331 
    332       switch (shdr1->sh_type)
    333 	{
    334 	case SHT_DYNSYM:
    335 	case SHT_SYMTAB:
    336 	  /* Iterate over the symbol table.  We ignore the st_size
    337 	     value of undefined symbols.  */
    338 	  for (int ndx = 0; ndx < (int) (shdr1->sh_size / shdr1->sh_entsize);
    339 	       ++ndx)
    340 	    {
    341 	      GElf_Sym sym1_mem;
    342 	      GElf_Sym *sym1 = gelf_getsym (data1, ndx, &sym1_mem);
    343 	      if (sym1 == NULL)
    344 		error (2, 0,
    345 		       gettext ("cannot get symbol in '%s': %s"),
    346 		       fname1, elf_errmsg (-1));
    347 	      GElf_Sym sym2_mem;
    348 	      GElf_Sym *sym2 = gelf_getsym (data2, ndx, &sym2_mem);
    349 	      if (sym2 == NULL)
    350 		error (2, 0,
    351 		       gettext ("cannot get symbol in '%s': %s"),
    352 		       fname2, elf_errmsg (-1));
    353 
    354 	      const char *name1 = elf_strptr (elf1, shdr1->sh_link,
    355 					      sym1->st_name);
    356 	      const char *name2 = elf_strptr (elf2, shdr2->sh_link,
    357 					      sym2->st_name);
    358 	      if (unlikely (name1 == NULL || name2 == NULL
    359 			    || strcmp (name1, name2) != 0
    360 			    || sym1->st_value != sym2->st_value
    361 			    || (sym1->st_size != sym2->st_size
    362 				&& sym1->st_shndx != SHN_UNDEF)
    363 			    || sym1->st_info != sym2->st_info
    364 			    || sym1->st_other != sym2->st_other
    365 			    || sym1->st_shndx != sym1->st_shndx))
    366 		{
    367 		  // XXX Do we want to allow reordered symbol tables?
    368 		symtab_mismatch:
    369 		  if (! quiet)
    370 		    {
    371 		      if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
    372 			error (0, 0,
    373 			       gettext ("%s %s differ: symbol table [%zu]"),
    374 			       fname1, fname2, elf_ndxscn (scn1));
    375 		      else
    376 			error (0, 0, gettext ("\
    377 %s %s differ: symbol table [%zu,%zu]"),
    378 			       fname1, fname2, elf_ndxscn (scn1),
    379 			       elf_ndxscn (scn2));
    380 		    }
    381 		  DIFFERENCE;
    382 		  break;
    383 		}
    384 
    385 	      if (sym1->st_shndx == SHN_UNDEF
    386 		  && sym1->st_size != sym2->st_size)
    387 		{
    388 		  /* The size of the symbol in the object defining it
    389 		     might have changed.  That is OK unless the symbol
    390 		     is used in a copy relocation.  Look over the
    391 		     sections in both files and determine which
    392 		     relocation section uses this symbol table
    393 		     section.  Then look through the relocations to
    394 		     see whether any copy relocation references this
    395 		     symbol.  */
    396 		  if (search_for_copy_reloc (ebl1, elf_ndxscn (scn1), ndx)
    397 		      || search_for_copy_reloc (ebl2, elf_ndxscn (scn2), ndx))
    398 		    goto symtab_mismatch;
    399 		}
    400 	    }
    401 	  break;
    402 
    403 	case SHT_NOTE:
    404 	  /* Parse the note format and compare the notes themselves.  */
    405 	  {
    406 	    GElf_Nhdr note1;
    407 	    GElf_Nhdr note2;
    408 
    409 	    size_t off1 = 0;
    410 	    size_t off2 = 0;
    411 	    size_t name_offset;
    412 	    size_t desc_offset;
    413 	    while (off1 < data1->d_size
    414 		   && (off1 = gelf_getnote (data1, off1, &note1,
    415 					    &name_offset, &desc_offset)) > 0)
    416 	      {
    417 		const char *name1 = data1->d_buf + name_offset;
    418 		const void *desc1 = data1->d_buf + desc_offset;
    419 		if (off2 >= data2->d_size)
    420 		  {
    421 		    if (! quiet)
    422 		      error (0, 0, gettext ("\
    423 %s %s differ: section [%zu] '%s' number of notes"),
    424 			     fname1, fname2, elf_ndxscn (scn1), sname1);
    425 		    DIFFERENCE;
    426 		  }
    427 		off2 = gelf_getnote (data2, off2, &note2,
    428 				     &name_offset, &desc_offset);
    429 		if (off2 == 0)
    430 		  error (2, 0, gettext ("\
    431 cannot read note section [%zu] '%s' in '%s': %s"),
    432 			 elf_ndxscn (scn2), sname2, fname2, elf_errmsg (-1));
    433 		const char *name2 = data2->d_buf + name_offset;
    434 		const void *desc2 = data2->d_buf + desc_offset;
    435 
    436 		if (note1.n_namesz != note2.n_namesz
    437 		    || memcmp (name1, name2, note1.n_namesz))
    438 		  {
    439 		    if (! quiet)
    440 		      error (0, 0, gettext ("\
    441 %s %s differ: section [%zu] '%s' note name"),
    442 			     fname1, fname2, elf_ndxscn (scn1), sname1);
    443 		    DIFFERENCE;
    444 		  }
    445 		if (note1.n_type != note2.n_type)
    446 		  {
    447 		    if (! quiet)
    448 		      error (0, 0, gettext ("\
    449 %s %s differ: section [%zu] '%s' note '%s' type"),
    450 			     fname1, fname2, elf_ndxscn (scn1), sname1, name1);
    451 		    DIFFERENCE;
    452 		  }
    453 		if (note1.n_descsz != note2.n_descsz
    454 		    || memcmp (desc1, desc2, note1.n_descsz))
    455 		  {
    456 		    if (note1.n_type == NT_GNU_BUILD_ID
    457 			&& note1.n_namesz == sizeof "GNU"
    458 			&& !memcmp (name1, "GNU", sizeof "GNU"))
    459 		      {
    460 			if (note1.n_descsz != note2.n_descsz)
    461 			  {
    462 			    if (! quiet)
    463 			      error (0, 0, gettext ("\
    464 %s %s differ: build ID length"),
    465 				     fname1, fname2);
    466 			    DIFFERENCE;
    467 			  }
    468 			else if (! ignore_build_id)
    469 			  {
    470 			    if (! quiet)
    471 			      error (0, 0, gettext ("\
    472 %s %s differ: build ID content"),
    473 				     fname1, fname2);
    474 			    DIFFERENCE;
    475 			  }
    476 		      }
    477 		    else
    478 		      {
    479 			if (! quiet)
    480 			  error (0, 0, gettext ("\
    481 %s %s differ: section [%zu] '%s' note '%s' content"),
    482 				 fname1, fname2, elf_ndxscn (scn1), sname1,
    483 				 name1);
    484 			DIFFERENCE;
    485 		      }
    486 		  }
    487 	      }
    488 	    if (off2 < data2->d_size)
    489 	      {
    490 		if (! quiet)
    491 		  error (0, 0, gettext ("\
    492 %s %s differ: section [%zu] '%s' number of notes"),
    493 			 fname1, fname2, elf_ndxscn (scn1), sname1);
    494 		DIFFERENCE;
    495 	      }
    496 	  }
    497 	  break;
    498 
    499 	default:
    500 	  /* Compare the section content byte for byte.  */
    501 	  assert (shdr1->sh_type == SHT_NOBITS
    502 		  || (data1->d_buf != NULL || data1->d_size == 0));
    503 	  assert (shdr2->sh_type == SHT_NOBITS
    504 		  || (data2->d_buf != NULL || data1->d_size == 0));
    505 
    506 	  if (unlikely (data1->d_size != data2->d_size
    507 			|| (shdr1->sh_type != SHT_NOBITS
    508 			    && memcmp (data1->d_buf, data2->d_buf,
    509 				       data1->d_size) != 0)))
    510 	    {
    511 	      if (hash_inexact
    512 		  && shdr1->sh_type == SHT_HASH
    513 		  && data1->d_size == data2->d_size
    514 		  && hash_content_equivalent (shdr1->sh_entsize, data1, data2))
    515 		break;
    516 
    517 	      if (! quiet)
    518 		{
    519 		  if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
    520 		    error (0, 0, gettext ("\
    521 %s %s differ: section [%zu] '%s' content"),
    522 			   fname1, fname2, elf_ndxscn (scn1), sname1);
    523 		  else
    524 		    error (0, 0, gettext ("\
    525 %s %s differ: section [%zu,%zu] '%s' content"),
    526 			   fname1, fname2, elf_ndxscn (scn1),
    527 			   elf_ndxscn (scn2), sname1);
    528 		}
    529 	      DIFFERENCE;
    530 	    }
    531 	  break;
    532 	}
    533     }
    534 
    535   if (unlikely (scn1 != scn2))
    536     {
    537       if (! quiet)
    538 	error (0, 0,
    539 	       gettext ("%s %s differ: unequal amount of important sections"),
    540 	       fname1, fname2);
    541       DIFFERENCE;
    542     }
    543 
    544   /* We we look at gaps, create artificial ones for the parts of the
    545      program which we are not in sections.  */
    546   struct region ehdr_region;
    547   struct region phdr_region;
    548   if (gaps != gaps_ignore)
    549     {
    550       ehdr_region.from = 0;
    551       ehdr_region.to = ehdr1->e_ehsize;
    552       ehdr_region.next = &phdr_region;
    553 
    554       phdr_region.from = ehdr1->e_phoff;
    555       phdr_region.to = ehdr1->e_phoff + phnum1 * ehdr1->e_phentsize;
    556       phdr_region.next = regions;
    557 
    558       regions = &ehdr_region;
    559       nregions += 2;
    560     }
    561 
    562   /* If we need to look at the gaps we need access to the file data.  */
    563   char *raw1 = NULL;
    564   size_t size1 = 0;
    565   char *raw2 = NULL;
    566   size_t size2 = 0;
    567   struct region *regionsarr = alloca (nregions * sizeof (struct region));
    568   if (gaps != gaps_ignore)
    569     {
    570       raw1 = elf_rawfile (elf1, &size1);
    571       if (raw1 == NULL )
    572 	error (2, 0, gettext ("cannot load data of '%s': %s"),
    573 	       fname1, elf_errmsg (-1));
    574 
    575       raw2 = elf_rawfile (elf2, &size2);
    576       if (raw2 == NULL )
    577 	error (2, 0, gettext ("cannot load data of '%s': %s"),
    578 	       fname2, elf_errmsg (-1));
    579 
    580       for (size_t cnt = 0; cnt < nregions; ++cnt)
    581 	{
    582 	  regionsarr[cnt] = *regions;
    583 	  regions = regions->next;
    584 	}
    585 
    586       qsort (regionsarr, nregions, sizeof (regionsarr[0]), regioncompare);
    587     }
    588 
    589   /* Compare the program header tables.  */
    590   for (unsigned int ndx = 0; ndx < phnum1; ++ndx)
    591     {
    592       GElf_Phdr phdr1_mem;
    593       GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem);
    594       if (ehdr1 == NULL)
    595 	error (2, 0,
    596 	       gettext ("cannot get program header entry %d of '%s': %s"),
    597 	       ndx, fname1, elf_errmsg (-1));
    598       GElf_Phdr phdr2_mem;
    599       GElf_Phdr *phdr2 = gelf_getphdr (elf2, ndx, &phdr2_mem);
    600       if (ehdr2 == NULL)
    601 	error (2, 0,
    602 	       gettext ("cannot get program header entry %d of '%s': %s"),
    603 	       ndx, fname2, elf_errmsg (-1));
    604 
    605       if (unlikely (memcmp (phdr1, phdr2, sizeof (GElf_Phdr)) != 0))
    606 	{
    607 	  if (! quiet)
    608 	    error (0, 0, gettext ("%s %s differ: program header %d"),
    609 		   fname1, fname2, ndx);
    610 	  DIFFERENCE;
    611 	}
    612 
    613       if (gaps != gaps_ignore && phdr1->p_type == PT_LOAD)
    614 	{
    615 	  size_t cnt = 0;
    616 	  while (cnt < nregions && regionsarr[cnt].to < phdr1->p_offset)
    617 	    ++cnt;
    618 
    619 	  GElf_Off last = phdr1->p_offset;
    620 	  GElf_Off end = phdr1->p_offset + phdr1->p_filesz;
    621 	  while (cnt < nregions && regionsarr[cnt].from < end)
    622 	    {
    623 	      if (last < regionsarr[cnt].from)
    624 		{
    625 		  /* Compare the [LAST,FROM) region.  */
    626 		  assert (gaps == gaps_match);
    627 		  if (unlikely (memcmp (raw1 + last, raw2 + last,
    628 					regionsarr[cnt].from - last) != 0))
    629 		    {
    630 		    gapmismatch:
    631 		      if (!quiet)
    632 			error (0, 0, gettext ("%s %s differ: gap"),
    633 			       fname1, fname2);
    634 		      DIFFERENCE;
    635 		      break;
    636 		    }
    637 
    638 		}
    639 	      last = regionsarr[cnt].to;
    640 	      ++cnt;
    641 	    }
    642 
    643 	  if (cnt == nregions && last < end)
    644 	    goto gapmismatch;
    645 	}
    646     }
    647 
    648  out:
    649   elf_end (elf1);
    650   elf_end (elf2);
    651   close (fd1);
    652   close (fd2);
    653 
    654   return result;
    655 }
    656 
    657 
    658 /* Print the version information.  */
    659 static void
    660 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
    661 {
    662   fprintf (stream, "elfcmp (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
    663   fprintf (stream, gettext ("\
    664 Copyright (C) %s Red Hat, Inc.\n\
    665 This is free software; see the source for copying conditions.  There is NO\n\
    666 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
    667 "), "2012");
    668   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
    669 }
    670 
    671 
    672 /* Handle program arguments.  */
    673 static error_t
    674 parse_opt (int key, char *arg,
    675 	   struct argp_state *state __attribute__ ((unused)))
    676 {
    677   switch (key)
    678     {
    679     case 'q':
    680       quiet = true;
    681       break;
    682 
    683     case 'l':
    684       verbose = true;
    685       break;
    686 
    687     case OPT_GAPS:
    688       if (strcasecmp (arg, "ignore") == 0)
    689 	gaps = gaps_ignore;
    690       else if (likely (strcasecmp (arg, "match") == 0))
    691 	gaps = gaps_match;
    692       else
    693 	{
    694 	  fprintf (stderr,
    695 		   gettext ("Invalid value '%s' for --gaps parameter."),
    696 		   arg);
    697 	  argp_help (&argp, stderr, ARGP_HELP_SEE,
    698 		     program_invocation_short_name);
    699 	  exit (1);
    700 	}
    701       break;
    702 
    703     case OPT_HASH_INEXACT:
    704       hash_inexact = true;
    705       break;
    706 
    707     case OPT_IGNORE_BUILD_ID:
    708       ignore_build_id = true;
    709       break;
    710 
    711     default:
    712       return ARGP_ERR_UNKNOWN;
    713     }
    714   return 0;
    715 }
    716 
    717 
    718 static Elf *
    719 open_file (const char *fname, int *fdp, Ebl **eblp)
    720 {
    721   int fd = open (fname, O_RDONLY);
    722   if (unlikely (fd == -1))
    723     error (2, errno, gettext ("cannot open '%s'"), fname);
    724   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
    725   if (elf == NULL)
    726     error (2, 0,
    727 	   gettext ("cannot create ELF descriptor for '%s': %s"),
    728 	   fname, elf_errmsg (-1));
    729   Ebl *ebl = ebl_openbackend (elf);
    730   if (ebl == NULL)
    731     error (2, 0,
    732 	   gettext ("cannot create EBL descriptor for '%s'"), fname);
    733 
    734   *fdp = fd;
    735   *eblp = ebl;
    736   return elf;
    737 }
    738 
    739 
    740 static bool
    741 search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx)
    742 {
    743   Elf_Scn *scn = NULL;
    744   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    745     {
    746       GElf_Shdr shdr_mem;
    747       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    748       if (shdr == NULL)
    749 	error (2, 0,
    750 	       gettext ("cannot get section header of section %zu: %s"),
    751 	       elf_ndxscn (scn), elf_errmsg (-1));
    752 
    753       if ((shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
    754 	  || shdr->sh_link != scnndx)
    755 	continue;
    756 
    757       Elf_Data *data = elf_getdata (scn, NULL);
    758       if (data == NULL)
    759 	error (2, 0,
    760 	       gettext ("cannot get content of section %zu: %s"),
    761 	       elf_ndxscn (scn), elf_errmsg (-1));
    762 
    763       if (shdr->sh_type == SHT_REL)
    764 	for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
    765 	     ++ndx)
    766 	  {
    767 	    GElf_Rel rel_mem;
    768 	    GElf_Rel *rel = gelf_getrel (data, ndx, &rel_mem);
    769 	    if (rel == NULL)
    770 	      error (2, 0, gettext ("cannot get relocation: %s"),
    771 		     elf_errmsg (-1));
    772 
    773 	    if ((int) GELF_R_SYM (rel->r_info) == symndx
    774 		&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
    775 	      return true;
    776 	  }
    777       else
    778 	for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
    779 	     ++ndx)
    780 	  {
    781 	    GElf_Rela rela_mem;
    782 	    GElf_Rela *rela = gelf_getrela (data, ndx, &rela_mem);
    783 	    if (rela == NULL)
    784 	      error (2, 0, gettext ("cannot get relocation: %s"),
    785 		     elf_errmsg (-1));
    786 
    787 	    if ((int) GELF_R_SYM (rela->r_info) == symndx
    788 		&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
    789 	      return true;
    790 	  }
    791     }
    792 
    793   return false;
    794 }
    795 
    796 
    797 static int
    798 regioncompare (const void *p1, const void *p2)
    799 {
    800   const struct region *r1 = (const struct region *) p1;
    801   const struct region *r2 = (const struct region *) p2;
    802 
    803   if (r1->from < r2->from)
    804     return -1;
    805   return 1;
    806 }
    807 
    808 
    809 static int
    810 compare_Elf32_Word (const void *p1, const void *p2)
    811 {
    812   const Elf32_Word *w1 = p1;
    813   const Elf32_Word *w2 = p2;
    814   return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
    815 }
    816 
    817 static int
    818 compare_Elf64_Xword (const void *p1, const void *p2)
    819 {
    820   const Elf64_Xword *w1 = p1;
    821   const Elf64_Xword *w2 = p2;
    822   return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
    823 }
    824 
    825 static bool
    826 hash_content_equivalent (size_t entsize, Elf_Data *data1, Elf_Data *data2)
    827 {
    828 #define CHECK_HASH(Hash_Word)						      \
    829   {									      \
    830     const Hash_Word *const hash1 = data1->d_buf;			      \
    831     const Hash_Word *const hash2 = data2->d_buf;			      \
    832     const size_t nbucket = hash1[0];					      \
    833     const size_t nchain = hash1[1];					      \
    834     if (data1->d_size != (2 + nbucket + nchain) * sizeof hash1[0]	      \
    835 	|| hash2[0] != nbucket || hash2[1] != nchain)			      \
    836       return false;							      \
    837 									      \
    838     const Hash_Word *const bucket1 = &hash1[2];				      \
    839     const Hash_Word *const chain1 = &bucket1[nbucket];			      \
    840     const Hash_Word *const bucket2 = &hash2[2];				      \
    841     const Hash_Word *const chain2 = &bucket2[nbucket];			      \
    842 									      \
    843     bool chain_ok[nchain];						      \
    844     Hash_Word temp1[nchain - 1];					      \
    845     Hash_Word temp2[nchain - 1];					      \
    846     memset (chain_ok, 0, sizeof chain_ok);				      \
    847     for (size_t i = 0; i < nbucket; ++i)				      \
    848       {									      \
    849 	if (bucket1[i] >= nchain || bucket2[i] >= nchain)		      \
    850 	  return false;							      \
    851 									      \
    852 	size_t b1 = 0;							      \
    853 	for (size_t p = bucket1[i]; p != STN_UNDEF; p = chain1[p])	      \
    854 	  if (p >= nchain || b1 >= nchain - 1)				      \
    855 	    return false;						      \
    856 	  else								      \
    857 	    temp1[b1++] = p;						      \
    858 									      \
    859 	size_t b2 = 0;							      \
    860 	for (size_t p = bucket2[i]; p != STN_UNDEF; p = chain2[p])	      \
    861 	  if (p >= nchain || b2 >= nchain - 1)				      \
    862 	    return false;						      \
    863 	  else								      \
    864 	    temp2[b2++] = p;						      \
    865 									      \
    866 	if (b1 != b2)							      \
    867 	  return false;							      \
    868 									      \
    869 	qsort (temp1, b1, sizeof temp1[0], compare_##Hash_Word);	      \
    870 	qsort (temp2, b2, sizeof temp2[0], compare_##Hash_Word);	      \
    871 									      \
    872 	for (b1 = 0; b1 < b2; ++b1)					      \
    873 	  if (temp1[b1] != temp2[b1])					      \
    874 	    return false;						      \
    875 	  else								      \
    876 	    chain_ok[temp1[b1]] = true;					      \
    877       }									      \
    878 									      \
    879     for (size_t i = 0; i < nchain; ++i)					      \
    880       if (!chain_ok[i] && chain1[i] != chain2[i])			      \
    881 	return false;							      \
    882 									      \
    883     return true;							      \
    884   }
    885 
    886   switch (entsize)
    887     {
    888     case 4:
    889       CHECK_HASH (Elf32_Word);
    890       break;
    891     case 8:
    892       CHECK_HASH (Elf64_Xword);
    893       break;
    894     }
    895 
    896   return false;
    897 }
    898 
    899 
    900 #include "debugpred.h"
    901