Home | History | Annotate | Download | only in src
      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 (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 (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 ("\
    437 cannot 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.  */
    668 static void
    669 print_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 ("\
    673 Copyright (C) %s Red Hat, Inc.\n\
    674 This is free software; see the source for copying conditions.  There is NO\n\
    675 warranty; 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.  */
    682 static error_t
    683 parse_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 
    727 static Elf *
    728 open_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 
    749 static bool
    750 search_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 
    806 static int
    807 regioncompare (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 
    818 static int
    819 compare_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 
    826 static int
    827 compare_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 
    834 static bool
    835 hash_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