Blame src/elfcmp.c

Packit Service 97d2fb
/* Compare relevant content of two ELF files.
Packit Service 97d2fb
   Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of the GNU General Public License as published by
Packit Service 97d2fb
   the Free Software Foundation; either version 3 of the License, or
Packit Service 97d2fb
   (at your option) any later version.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 97d2fb
   GNU General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received a copy of the GNU General Public License
Packit Service 97d2fb
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <locale.h>
Packit Service 97d2fb
#include <libintl.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <printversion.h>
Packit Service 97d2fb
#include "../libelf/elf-knowledge.h"
Packit Service 97d2fb
#include "../libebl/libeblP.h"
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
Packit Service 97d2fb
/* Prototypes of local functions.  */
Packit Service 97d2fb
static Elf *open_file (const char *fname, int *fdp, Ebl **eblp);
Packit Service 97d2fb
static bool search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx);
Packit Service 97d2fb
static  int regioncompare (const void *p1, const void *p2);
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Name and version of program.  */
Packit Service 97d2fb
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Packit Service 97d2fb
Packit Service 97d2fb
/* Bug report address.  */
Packit Service 97d2fb
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Packit Service 97d2fb
Packit Service 97d2fb
/* Values for the parameters which have no short form.  */
Packit Service 97d2fb
#define OPT_GAPS		0x100
Packit Service 97d2fb
#define OPT_HASH_INEXACT	0x101
Packit Service 97d2fb
#define OPT_IGNORE_BUILD_ID	0x102
Packit Service 97d2fb
Packit Service 97d2fb
/* Definitions of arguments for argp functions.  */
Packit Service 97d2fb
static const struct argp_option options[] =
Packit Service 97d2fb
{
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Control options:"), 0 },
Packit Service 97d2fb
  { "verbose", 'l', NULL, 0,
Packit Service 97d2fb
    N_("Output all differences, not just the first"), 0 },
Packit Service 97d2fb
  { "gaps", OPT_GAPS, "ACTION", 0, N_("Control treatment of gaps in loadable segments [ignore|match] (default: ignore)"), 0 },
Packit Service 97d2fb
  { "hash-inexact", OPT_HASH_INEXACT, NULL, 0,
Packit Service 97d2fb
    N_("Ignore permutation of buckets in SHT_HASH section"), 0 },
Packit Service 97d2fb
  { "ignore-build-id", OPT_IGNORE_BUILD_ID, NULL, 0,
Packit Service 97d2fb
    N_("Ignore differences in build ID"), 0 },
Packit Service 97d2fb
  { "quiet", 'q', NULL, 0, N_("Output nothing; yield exit status only"), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
Packit Service 97d2fb
  { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Short description of program.  */
Packit Service 97d2fb
static const char doc[] = N_("\
Packit Service 97d2fb
Compare relevant parts of two ELF files for equality.");
Packit Service 97d2fb
Packit Service 97d2fb
/* Strings for arguments in help texts.  */
Packit Service 97d2fb
static const char args_doc[] = N_("FILE1 FILE2");
Packit Service 97d2fb
Packit Service 97d2fb
/* Prototype for option handler.  */
Packit Service 97d2fb
static error_t parse_opt (int key, char *arg, struct argp_state *state);
Packit Service 97d2fb
Packit Service 97d2fb
/* Data structure to communicate with argp functions.  */
Packit Service 97d2fb
static struct argp argp =
Packit Service 97d2fb
{
Packit Service 97d2fb
  options, parse_opt, args_doc, doc, NULL, NULL, NULL
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* How to treat gaps in loadable segments.  */
Packit Service 97d2fb
static enum
Packit Service 97d2fb
  {
Packit Service 97d2fb
    gaps_ignore = 0,
Packit Service 97d2fb
    gaps_match
Packit Service 97d2fb
  }
Packit Service 97d2fb
  gaps;
Packit Service 97d2fb
Packit Service 97d2fb
/* Structure to hold information about used regions.  */
Packit Service 97d2fb
struct region
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Addr from;
Packit Service 97d2fb
  GElf_Addr to;
Packit Service 97d2fb
  struct region *next;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Nonzero if only exit status is wanted.  */
Packit Service 97d2fb
static bool quiet;
Packit Service 97d2fb
Packit Service 97d2fb
/* True iff multiple differences should be output.  */
Packit Service 97d2fb
static bool verbose;
Packit Service 97d2fb
Packit Service 97d2fb
/* True iff SHT_HASH treatment should be generous.  */
Packit Service 97d2fb
static bool hash_inexact;
Packit Service 97d2fb
Packit Service 97d2fb
/* True iff build ID notes should be ignored.  */
Packit Service 97d2fb
static bool ignore_build_id;
Packit Service 97d2fb
Packit Service 97d2fb
static bool hash_content_equivalent (size_t entsize, Elf_Data *, Elf_Data *);
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc, char *argv[])
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Set locale.  */
Packit Service 97d2fb
  (void) setlocale (LC_ALL, "");
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure the message catalog can be found.  */
Packit Service 97d2fb
  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Initialize the message catalog.  */
Packit Service 97d2fb
  (void) textdomain (PACKAGE_TARNAME);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Parse and process arguments.  */
Packit Service 97d2fb
  int remaining;
Packit Service 97d2fb
  (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We expect exactly two non-option parameters.  */
Packit Service 97d2fb
  if (unlikely (remaining + 2 != argc))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      fputs (gettext ("Invalid number of parameters.\n"), stderr);
Packit Service 97d2fb
      argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
Packit Service 97d2fb
      exit (1);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (quiet)
Packit Service 97d2fb
    verbose = false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Comparing the files is done in two phases:
Packit Service 97d2fb
     1. compare all sections.  Sections which are irrelevant (i.e., if
Packit Service 97d2fb
	strip would remove them) are ignored.  Some section types are
Packit Service 97d2fb
	handled special.
Packit Service 97d2fb
     2. all parts of the loadable segments which are not parts of any
Packit Service 97d2fb
	section is compared according to the rules of the --gaps option.
Packit Service 97d2fb
  */
Packit Service 97d2fb
  int result = 0;
Packit Service 97d2fb
  elf_version (EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  const char *const fname1 = argv[remaining];
Packit Service 97d2fb
  int fd1;
Packit Service 97d2fb
  Ebl *ebl1;
Packit Service 97d2fb
  Elf *elf1 = open_file (fname1, &fd1, &ebl1);
Packit Service 97d2fb
Packit Service 97d2fb
  const char *const fname2 = argv[remaining + 1];
Packit Service 97d2fb
  int fd2;
Packit Service 97d2fb
  Ebl *ebl2;
Packit Service 97d2fb
  Elf *elf2 = open_file (fname2, &fd2, &ebl2);
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr ehdr1_mem;
Packit Service 97d2fb
  GElf_Ehdr *ehdr1 = gelf_getehdr (elf1, &ehdr1_mem);
Packit Service 97d2fb
  if (ehdr1 == NULL)
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get ELF header of '%s': %s"),
Packit Service 97d2fb
	   fname1, elf_errmsg (-1));
Packit Service 97d2fb
  GElf_Ehdr ehdr2_mem;
Packit Service 97d2fb
  GElf_Ehdr *ehdr2 = gelf_getehdr (elf2, &ehdr2_mem);
Packit Service 97d2fb
  if (ehdr2 == NULL)
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get ELF header of '%s': %s"),
Packit Service 97d2fb
	   fname2, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
#define DIFFERENCE							      \
Packit Service 97d2fb
  do									      \
Packit Service 97d2fb
    {									      \
Packit Service 97d2fb
      result = 1;							      \
Packit Service 97d2fb
      if (! verbose)							      \
Packit Service 97d2fb
	goto out;							      \
Packit Service 97d2fb
    }									      \
Packit Service 97d2fb
  while (0)
Packit Service 97d2fb
Packit Service 97d2fb
  /* Compare the ELF headers.  */
Packit Service 97d2fb
  if (unlikely (memcmp (ehdr1->e_ident, ehdr2->e_ident, EI_NIDENT) != 0
Packit Service 97d2fb
		|| ehdr1->e_type != ehdr2->e_type
Packit Service 97d2fb
		|| ehdr1->e_machine != ehdr2->e_machine
Packit Service 97d2fb
		|| ehdr1->e_version != ehdr2->e_version
Packit Service 97d2fb
		|| ehdr1->e_entry != ehdr2->e_entry
Packit Service 97d2fb
		|| ehdr1->e_phoff != ehdr2->e_phoff
Packit Service 97d2fb
		|| ehdr1->e_flags != ehdr2->e_flags
Packit Service 97d2fb
		|| ehdr1->e_ehsize != ehdr2->e_ehsize
Packit Service 97d2fb
		|| ehdr1->e_phentsize != ehdr2->e_phentsize
Packit Service 97d2fb
		|| ehdr1->e_phnum != ehdr2->e_phnum
Packit Service 97d2fb
		|| ehdr1->e_shentsize != ehdr2->e_shentsize))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (! quiet)
Packit Service 97d2fb
	error (0, 0, gettext ("%s %s diff: ELF header"), fname1, fname2);
Packit Service 97d2fb
      DIFFERENCE;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shnum1;
Packit Service 97d2fb
  size_t shnum2;
Packit Service 97d2fb
  if (unlikely (elf_getshdrnum (elf1, &shnum1) != 0))
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get section count of '%s': %s"),
Packit Service 97d2fb
	   fname1, elf_errmsg (-1));
Packit Service 97d2fb
  if (unlikely (elf_getshdrnum (elf2, &shnum2) != 0))
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get section count of '%s': %s"),
Packit Service 97d2fb
	   fname2, elf_errmsg (-1));
Packit Service 97d2fb
  if (unlikely (shnum1 != shnum2))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (! quiet)
Packit Service 97d2fb
	error (0, 0, gettext ("%s %s diff: section count"), fname1, fname2);
Packit Service 97d2fb
      DIFFERENCE;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  size_t phnum1;
Packit Service 97d2fb
  size_t phnum2;
Packit Service 97d2fb
  if (unlikely (elf_getphdrnum (elf1, &phnum1) != 0))
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get program header count of '%s': %s"),
Packit Service 97d2fb
	   fname1, elf_errmsg (-1));
Packit Service 97d2fb
  if (unlikely (elf_getphdrnum (elf2, &phnum2) != 0))
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get program header count of '%s': %s"),
Packit Service 97d2fb
	   fname2, elf_errmsg (-1));
Packit Service 97d2fb
  if (unlikely (phnum1 != phnum2))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (! quiet)
Packit Service 97d2fb
	error (0, 0, gettext ("%s %s diff: program header count"),
Packit Service 97d2fb
	       fname1, fname2);
Packit Service 97d2fb
      DIFFERENCE;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shstrndx1;
Packit Service 97d2fb
  size_t shstrndx2;
Packit Service 97d2fb
  if (elf_getshdrstrndx (elf1, &shstrndx1) != 0)
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get hdrstrndx of '%s': %s"),
Packit Service 97d2fb
	   fname1, elf_errmsg (-1));
Packit Service 97d2fb
  if (elf_getshdrstrndx (elf2, &shstrndx2) != 0)
Packit Service 97d2fb
    error (2, 0, gettext ("cannot get hdrstrndx of '%s': %s"),
Packit Service 97d2fb
	   fname2, elf_errmsg (-1));
Packit Service 97d2fb
  if (shstrndx1 != shstrndx2)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (! quiet)
Packit Service 97d2fb
	error (0, 0, gettext ("%s %s diff: shdr string index"),
Packit Service 97d2fb
	       fname1, fname2);
Packit Service 97d2fb
      DIFFERENCE;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Iterate over all sections.  We expect the sections in the two
Packit Service 97d2fb
     files to match exactly.  */
Packit Service 97d2fb
  Elf_Scn *scn1 = NULL;
Packit Service 97d2fb
  Elf_Scn *scn2 = NULL;
Packit Service 97d2fb
  struct region *regions = NULL;
Packit Service 97d2fb
  size_t nregions = 0;
Packit Service 97d2fb
  while (1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr1_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr1;
Packit Service 97d2fb
      const char *sname1 = NULL;
Packit Service 97d2fb
      do
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  scn1 = elf_nextscn (elf1, scn1);
Packit Service 97d2fb
	  shdr1 = gelf_getshdr (scn1, &shdr1_mem);
Packit Service 97d2fb
	  if (shdr1 != NULL)
Packit Service 97d2fb
	    sname1 = elf_strptr (elf1, shstrndx1, shdr1->sh_name);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      while (scn1 != NULL && shdr1 != NULL
Packit Service 97d2fb
	     && ebl_section_strip_p (ebl1, shdr1, sname1, true, false));
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Shdr shdr2_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr2;
Packit Service 97d2fb
      const char *sname2 = NULL;
Packit Service 97d2fb
      do
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  scn2 = elf_nextscn (elf2, scn2);
Packit Service 97d2fb
	  shdr2 = gelf_getshdr (scn2, &shdr2_mem);
Packit Service 97d2fb
	  if (shdr2 != NULL)
Packit Service 97d2fb
	    sname2 = elf_strptr (elf2, shstrndx2, shdr2->sh_name);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      while (scn2 != NULL && shdr2 != NULL
Packit Service 97d2fb
	     && ebl_section_strip_p (ebl2, shdr2, sname2, true, false));
Packit Service 97d2fb
Packit Service 97d2fb
      if (scn1 == NULL || scn2 == NULL || shdr1 == NULL || shdr2 == NULL)
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      if (gaps != gaps_ignore && (shdr1->sh_flags & SHF_ALLOC) != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  struct region *newp = (struct region *) alloca (sizeof (*newp));
Packit Service 97d2fb
	  newp->from = shdr1->sh_offset;
Packit Service 97d2fb
	  newp->to = shdr1->sh_offset + shdr1->sh_size;
Packit Service 97d2fb
	  newp->next = regions;
Packit Service 97d2fb
	  regions = newp;
Packit Service 97d2fb
Packit Service 97d2fb
	  ++nregions;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Compare the headers.  We allow the name to be at a different
Packit Service 97d2fb
	 location.  */
Packit Service 97d2fb
      if (unlikely (sname1 == NULL || sname2 == NULL
Packit Service 97d2fb
		    || strcmp (sname1, sname2) != 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  error (0, 0, gettext ("%s %s differ: section [%zu], [%zu] name"),
Packit Service 97d2fb
		 fname1, fname2, elf_ndxscn (scn1), elf_ndxscn (scn2));
Packit Service 97d2fb
	  DIFFERENCE;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We ignore certain sections.  */
Packit Service 97d2fb
      if ((sname1 != NULL && strcmp (sname1, ".gnu_debuglink") == 0)
Packit Service 97d2fb
	  || (sname1 != NULL && strcmp (sname1, ".gnu.prelink_undo") == 0))
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr1->sh_type != shdr2->sh_type
Packit Service 97d2fb
	  // XXX Any flags which should be ignored?
Packit Service 97d2fb
	  || shdr1->sh_flags != shdr2->sh_flags
Packit Service 97d2fb
	  || shdr1->sh_addr != shdr2->sh_addr
Packit Service 97d2fb
	  || (shdr1->sh_offset != shdr2->sh_offset
Packit Service 97d2fb
	      && (shdr1->sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	      && ehdr1->e_type != ET_REL)
Packit Service 97d2fb
	  || shdr1->sh_size != shdr2->sh_size
Packit Service 97d2fb
	  || shdr1->sh_link != shdr2->sh_link
Packit Service 97d2fb
	  || shdr1->sh_info != shdr2->sh_info
Packit Service 97d2fb
	  || shdr1->sh_addralign != shdr2->sh_addralign
Packit Service 97d2fb
	  || shdr1->sh_entsize != shdr2->sh_entsize)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  error (0, 0, gettext ("%s %s differ: section [%zu] '%s' header"),
Packit Service 97d2fb
		 fname1, fname2, elf_ndxscn (scn1), sname1);
Packit Service 97d2fb
	  DIFFERENCE;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *data1 = elf_getdata (scn1, NULL);
Packit Service 97d2fb
      if (data1 == NULL)
Packit Service 97d2fb
	error (2, 0,
Packit Service 97d2fb
	       gettext ("cannot get content of section %zu in '%s': %s"),
Packit Service 97d2fb
	       elf_ndxscn (scn1), fname1, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *data2 = elf_getdata (scn2, NULL);
Packit Service 97d2fb
      if (data2 == NULL)
Packit Service 97d2fb
	error (2, 0,
Packit Service 97d2fb
	       gettext ("cannot get content of section %zu in '%s': %s"),
Packit Service 97d2fb
	       elf_ndxscn (scn2), fname2, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      switch (shdr1->sh_type)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case SHT_DYNSYM:
Packit Service 97d2fb
	case SHT_SYMTAB:
Packit Service 97d2fb
	  if (shdr1->sh_entsize == 0)
Packit Service 97d2fb
	    error (2, 0,
Packit Service 97d2fb
		   gettext ("symbol table [%zu] in '%s' has zero sh_entsize"),
Packit Service 97d2fb
		   elf_ndxscn (scn1), fname1);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Iterate over the symbol table.  We ignore the st_size
Packit Service 97d2fb
	     value of undefined symbols.  */
Packit Service 97d2fb
	  for (int ndx = 0; ndx < (int) (shdr1->sh_size / shdr1->sh_entsize);
Packit Service 97d2fb
	       ++ndx)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      GElf_Sym sym1_mem;
Packit Service 97d2fb
	      GElf_Sym *sym1 = gelf_getsym (data1, ndx, &sym1_mem);
Packit Service 97d2fb
	      if (sym1 == NULL)
Packit Service 97d2fb
		error (2, 0,
Packit Service 97d2fb
		       gettext ("cannot get symbol in '%s': %s"),
Packit Service 97d2fb
		       fname1, elf_errmsg (-1));
Packit Service 97d2fb
	      GElf_Sym sym2_mem;
Packit Service 97d2fb
	      GElf_Sym *sym2 = gelf_getsym (data2, ndx, &sym2_mem);
Packit Service 97d2fb
	      if (sym2 == NULL)
Packit Service 97d2fb
		error (2, 0,
Packit Service 97d2fb
		       gettext ("cannot get symbol in '%s': %s"),
Packit Service 97d2fb
		       fname2, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
	      const char *name1 = elf_strptr (elf1, shdr1->sh_link,
Packit Service 97d2fb
					      sym1->st_name);
Packit Service 97d2fb
	      const char *name2 = elf_strptr (elf2, shdr2->sh_link,
Packit Service 97d2fb
					      sym2->st_name);
Packit Service 97d2fb
	      if (unlikely (name1 == NULL || name2 == NULL
Packit Service 97d2fb
			    || strcmp (name1, name2) != 0
Packit Service 97d2fb
			    || sym1->st_value != sym2->st_value
Packit Service 97d2fb
			    || (sym1->st_size != sym2->st_size
Packit Service 97d2fb
				&& sym1->st_shndx != SHN_UNDEF)
Packit Service 97d2fb
			    || sym1->st_info != sym2->st_info
Packit Service 97d2fb
			    || sym1->st_other != sym2->st_other
Packit Service 97d2fb
			    || sym1->st_shndx != sym2->st_shndx))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  // XXX Do we want to allow reordered symbol tables?
Packit Service 97d2fb
		symtab_mismatch:
Packit Service 97d2fb
		  if (! quiet)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
Packit Service 97d2fb
			error (0, 0,
Packit Service 97d2fb
			       gettext ("%s %s differ: symbol table [%zu]"),
Packit Service 97d2fb
			       fname1, fname2, elf_ndxscn (scn1));
Packit Service 97d2fb
		      else
Packit Service 97d2fb
			error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: symbol table [%zu,%zu]"),
Packit Service 97d2fb
			       fname1, fname2, elf_ndxscn (scn1),
Packit Service 97d2fb
			       elf_ndxscn (scn2));
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  DIFFERENCE;
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      if (sym1->st_shndx == SHN_UNDEF
Packit Service 97d2fb
		  && sym1->st_size != sym2->st_size)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* The size of the symbol in the object defining it
Packit Service 97d2fb
		     might have changed.  That is OK unless the symbol
Packit Service 97d2fb
		     is used in a copy relocation.  Look over the
Packit Service 97d2fb
		     sections in both files and determine which
Packit Service 97d2fb
		     relocation section uses this symbol table
Packit Service 97d2fb
		     section.  Then look through the relocations to
Packit Service 97d2fb
		     see whether any copy relocation references this
Packit Service 97d2fb
		     symbol.  */
Packit Service 97d2fb
		  if (search_for_copy_reloc (ebl1, elf_ndxscn (scn1), ndx)
Packit Service 97d2fb
		      || search_for_copy_reloc (ebl2, elf_ndxscn (scn2), ndx))
Packit Service 97d2fb
		    goto symtab_mismatch;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case SHT_NOTE:
Packit Service 97d2fb
	  /* Parse the note format and compare the notes themselves.  */
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    GElf_Nhdr note1;
Packit Service 97d2fb
	    GElf_Nhdr note2;
Packit Service 97d2fb
Packit Service 97d2fb
	    size_t off1 = 0;
Packit Service 97d2fb
	    size_t off2 = 0;
Packit Service 97d2fb
	    size_t name_offset;
Packit Service 97d2fb
	    size_t desc_offset;
Packit Service 97d2fb
	    while (off1 < data1->d_size
Packit Service 97d2fb
		   && (off1 = gelf_getnote (data1, off1, &note1,
Packit Service 97d2fb
					    &name_offset, &desc_offset)) > 0)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		const char *name1 = (note1.n_namesz == 0
Packit Service 97d2fb
				     ? "" : data1->d_buf + name_offset);
Packit Service 97d2fb
		const void *desc1 = data1->d_buf + desc_offset;
Packit Service 97d2fb
		if (off2 >= data2->d_size)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (! quiet)
Packit Service 97d2fb
		      error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu] '%s' number of notes"),
Packit Service 97d2fb
			     fname1, fname2, elf_ndxscn (scn1), sname1);
Packit Service 97d2fb
		    DIFFERENCE;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
		off2 = gelf_getnote (data2, off2, &note2,
Packit Service 97d2fb
				     &name_offset, &desc_offset);
Packit Service 97d2fb
		if (off2 == 0)
Packit Service 97d2fb
		  error (2, 0, gettext ("\
Packit Service 97d2fb
cannot read note section [%zu] '%s' in '%s': %s"),
Packit Service 97d2fb
			 elf_ndxscn (scn2), sname2, fname2, elf_errmsg (-1));
Packit Service 97d2fb
		const char *name2 = (note2.n_namesz == 0
Packit Service 97d2fb
				     ? "" : data2->d_buf + name_offset);
Packit Service 97d2fb
		const void *desc2 = data2->d_buf + desc_offset;
Packit Service 97d2fb
Packit Service 97d2fb
		if (note1.n_namesz != note2.n_namesz
Packit Service 97d2fb
		    || memcmp (name1, name2, note1.n_namesz))
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (! quiet)
Packit Service 97d2fb
		      error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu] '%s' note name"),
Packit Service 97d2fb
			     fname1, fname2, elf_ndxscn (scn1), sname1);
Packit Service 97d2fb
		    DIFFERENCE;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
		if (note1.n_type != note2.n_type)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (! quiet)
Packit Service 97d2fb
		      error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu] '%s' note '%s' type"),
Packit Service 97d2fb
			     fname1, fname2, elf_ndxscn (scn1), sname1, name1);
Packit Service 97d2fb
		    DIFFERENCE;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
		if (note1.n_descsz != note2.n_descsz
Packit Service 97d2fb
		    || memcmp (desc1, desc2, note1.n_descsz))
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (note1.n_type == NT_GNU_BUILD_ID
Packit Service 97d2fb
			&& note1.n_namesz == sizeof "GNU"
Packit Service 97d2fb
			&& !memcmp (name1, "GNU", sizeof "GNU"))
Packit Service 97d2fb
		      {
Packit Service 97d2fb
			if (note1.n_descsz != note2.n_descsz)
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    if (! quiet)
Packit Service 97d2fb
			      error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: build ID length"),
Packit Service 97d2fb
				     fname1, fname2);
Packit Service 97d2fb
			    DIFFERENCE;
Packit Service 97d2fb
			  }
Packit Service 97d2fb
			else if (! ignore_build_id)
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    if (! quiet)
Packit Service 97d2fb
			      error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: build ID content"),
Packit Service 97d2fb
				     fname1, fname2);
Packit Service 97d2fb
			    DIFFERENCE;
Packit Service 97d2fb
			  }
Packit Service 97d2fb
		      }
Packit Service 97d2fb
		    else
Packit Service 97d2fb
		      {
Packit Service 97d2fb
			if (! quiet)
Packit Service 97d2fb
			  error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu] '%s' note '%s' content"),
Packit Service 97d2fb
				 fname1, fname2, elf_ndxscn (scn1), sname1,
Packit Service 97d2fb
				 name1);
Packit Service 97d2fb
			DIFFERENCE;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
		  }
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    if (off2 < data2->d_size)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		if (! quiet)
Packit Service 97d2fb
		  error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu] '%s' number of notes"),
Packit Service 97d2fb
			 fname1, fname2, elf_ndxscn (scn1), sname1);
Packit Service 97d2fb
		DIFFERENCE;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  /* Compare the section content byte for byte.  */
Packit Service 97d2fb
	  assert (shdr1->sh_type == SHT_NOBITS
Packit Service 97d2fb
		  || (data1->d_buf != NULL || data1->d_size == 0));
Packit Service 97d2fb
	  assert (shdr2->sh_type == SHT_NOBITS
Packit Service 97d2fb
		  || (data2->d_buf != NULL || data1->d_size == 0));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (unlikely (data1->d_size != data2->d_size
Packit Service 97d2fb
			|| (shdr1->sh_type != SHT_NOBITS
Packit Service 97d2fb
			    && data1->d_size != 0
Packit Service 97d2fb
			    && memcmp (data1->d_buf, data2->d_buf,
Packit Service 97d2fb
				       data1->d_size) != 0)))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (hash_inexact
Packit Service 97d2fb
		  && shdr1->sh_type == SHT_HASH
Packit Service 97d2fb
		  && data1->d_size == data2->d_size
Packit Service 97d2fb
		  && hash_content_equivalent (shdr1->sh_entsize, data1, data2))
Packit Service 97d2fb
		break;
Packit Service 97d2fb
Packit Service 97d2fb
	      if (! quiet)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
Packit Service 97d2fb
		    error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu] '%s' content"),
Packit Service 97d2fb
			   fname1, fname2, elf_ndxscn (scn1), sname1);
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    error (0, 0, gettext ("\
Packit Service 97d2fb
%s %s differ: section [%zu,%zu] '%s' content"),
Packit Service 97d2fb
			   fname1, fname2, elf_ndxscn (scn1),
Packit Service 97d2fb
			   elf_ndxscn (scn2), sname1);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      DIFFERENCE;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (scn1 != scn2))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (! quiet)
Packit Service 97d2fb
	error (0, 0,
Packit Service 97d2fb
	       gettext ("%s %s differ: unequal amount of important sections"),
Packit Service 97d2fb
	       fname1, fname2);
Packit Service 97d2fb
      DIFFERENCE;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We we look at gaps, create artificial ones for the parts of the
Packit Service 97d2fb
     program which we are not in sections.  */
Packit Service 97d2fb
  struct region ehdr_region;
Packit Service 97d2fb
  struct region phdr_region;
Packit Service 97d2fb
  if (gaps != gaps_ignore)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ehdr_region.from = 0;
Packit Service 97d2fb
      ehdr_region.to = ehdr1->e_ehsize;
Packit Service 97d2fb
      ehdr_region.next = &phdr_region;
Packit Service 97d2fb
Packit Service 97d2fb
      phdr_region.from = ehdr1->e_phoff;
Packit Service 97d2fb
      phdr_region.to = ehdr1->e_phoff + phnum1 * ehdr1->e_phentsize;
Packit Service 97d2fb
      phdr_region.next = regions;
Packit Service 97d2fb
Packit Service 97d2fb
      regions = &ehdr_region;
Packit Service 97d2fb
      nregions += 2;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If we need to look at the gaps we need access to the file data.  */
Packit Service 97d2fb
  char *raw1 = NULL;
Packit Service 97d2fb
  size_t size1 = 0;
Packit Service 97d2fb
  char *raw2 = NULL;
Packit Service 97d2fb
  size_t size2 = 0;
Packit Service 97d2fb
  struct region *regionsarr = alloca (nregions * sizeof (struct region));
Packit Service 97d2fb
  if (gaps != gaps_ignore)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      raw1 = elf_rawfile (elf1, &size1);
Packit Service 97d2fb
      if (raw1 == NULL )
Packit Service 97d2fb
	error (2, 0, gettext ("cannot load data of '%s': %s"),
Packit Service 97d2fb
	       fname1, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      raw2 = elf_rawfile (elf2, &size2);
Packit Service 97d2fb
      if (raw2 == NULL )
Packit Service 97d2fb
	error (2, 0, gettext ("cannot load data of '%s': %s"),
Packit Service 97d2fb
	       fname2, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      for (size_t cnt = 0; cnt < nregions; ++cnt)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  regionsarr[cnt] = *regions;
Packit Service 97d2fb
	  regions = regions->next;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      qsort (regionsarr, nregions, sizeof (regionsarr[0]), regioncompare);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Compare the program header tables.  */
Packit Service 97d2fb
  for (unsigned int ndx = 0; ndx < phnum1; ++ndx)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Phdr phdr1_mem;
Packit Service 97d2fb
      GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem);
Packit Service 97d2fb
      if (phdr1 == NULL)
Packit Service 97d2fb
	error (2, 0,
Packit Service 97d2fb
	       gettext ("cannot get program header entry %d of '%s': %s"),
Packit Service 97d2fb
	       ndx, fname1, elf_errmsg (-1));
Packit Service 97d2fb
      GElf_Phdr phdr2_mem;
Packit Service 97d2fb
      GElf_Phdr *phdr2 = gelf_getphdr (elf2, ndx, &phdr2_mem);
Packit Service 97d2fb
      if (phdr2 == NULL)
Packit Service 97d2fb
	error (2, 0,
Packit Service 97d2fb
	       gettext ("cannot get program header entry %d of '%s': %s"),
Packit Service 97d2fb
	       ndx, fname2, elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (memcmp (phdr1, phdr2, sizeof (GElf_Phdr)) != 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (! quiet)
Packit Service 97d2fb
	    error (0, 0, gettext ("%s %s differ: program header %d"),
Packit Service 97d2fb
		   fname1, fname2, ndx);
Packit Service 97d2fb
	  DIFFERENCE;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (gaps != gaps_ignore && phdr1->p_type == PT_LOAD)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  size_t cnt = 0;
Packit Service 97d2fb
	  while (cnt < nregions && regionsarr[cnt].to < phdr1->p_offset)
Packit Service 97d2fb
	    ++cnt;
Packit Service 97d2fb
Packit Service 97d2fb
	  GElf_Off last = phdr1->p_offset;
Packit Service 97d2fb
	  GElf_Off end = phdr1->p_offset + phdr1->p_filesz;
Packit Service 97d2fb
	  while (cnt < nregions && regionsarr[cnt].from < end)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (last < regionsarr[cnt].from)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* Compare the [LAST,FROM) region.  */
Packit Service 97d2fb
		  assert (gaps == gaps_match);
Packit Service 97d2fb
		  if (unlikely (memcmp (raw1 + last, raw2 + last,
Packit Service 97d2fb
					regionsarr[cnt].from - last) != 0))
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		    gapmismatch:
Packit Service 97d2fb
		      if (!quiet)
Packit Service 97d2fb
			error (0, 0, gettext ("%s %s differ: gap"),
Packit Service 97d2fb
			       fname1, fname2);
Packit Service 97d2fb
		      DIFFERENCE;
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      last = regionsarr[cnt].to;
Packit Service 97d2fb
	      ++cnt;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (cnt == nregions && last < end)
Packit Service 97d2fb
	    goto gapmismatch;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
 out:
Packit Service 97d2fb
  elf_end (elf1);
Packit Service 97d2fb
  elf_end (elf2);
Packit Service 97d2fb
  ebl_closebackend (ebl1);
Packit Service 97d2fb
  ebl_closebackend (ebl2);
Packit Service 97d2fb
  close (fd1);
Packit Service 97d2fb
  close (fd2);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle program arguments.  */
Packit Service 97d2fb
static error_t
Packit Service 97d2fb
parse_opt (int key, char *arg,
Packit Service 97d2fb
	   struct argp_state *state __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (key)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 'q':
Packit Service 97d2fb
      quiet = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'l':
Packit Service 97d2fb
      verbose = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_GAPS:
Packit Service 97d2fb
      if (strcasecmp (arg, "ignore") == 0)
Packit Service 97d2fb
	gaps = gaps_ignore;
Packit Service 97d2fb
      else if (likely (strcasecmp (arg, "match") == 0))
Packit Service 97d2fb
	gaps = gaps_match;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  fprintf (stderr,
Packit Service 97d2fb
		   gettext ("Invalid value '%s' for --gaps parameter."),
Packit Service 97d2fb
		   arg);
Packit Service 97d2fb
	  argp_help (&argp, stderr, ARGP_HELP_SEE,
Packit Service 97d2fb
		     program_invocation_short_name);
Packit Service 97d2fb
	  exit (1);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_HASH_INEXACT:
Packit Service 97d2fb
      hash_inexact = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_IGNORE_BUILD_ID:
Packit Service 97d2fb
      ignore_build_id = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return ARGP_ERR_UNKNOWN;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static Elf *
Packit Service 97d2fb
open_file (const char *fname, int *fdp, Ebl **eblp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int fd = open (fname, O_RDONLY);
Packit Service 97d2fb
  if (unlikely (fd == -1))
Packit Service 97d2fb
    error (2, errno, gettext ("cannot open '%s'"), fname);
Packit Service 97d2fb
  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
Packit Service 97d2fb
  if (elf == NULL)
Packit Service 97d2fb
    error (2, 0,
Packit Service 97d2fb
	   gettext ("cannot create ELF descriptor for '%s': %s"),
Packit Service 97d2fb
	   fname, elf_errmsg (-1));
Packit Service 97d2fb
  Ebl *ebl = ebl_openbackend (elf);
Packit Service 97d2fb
  if (ebl == NULL)
Packit Service 97d2fb
    error (2, 0,
Packit Service 97d2fb
	   gettext ("cannot create EBL descriptor for '%s'"), fname);
Packit Service 97d2fb
Packit Service 97d2fb
  *fdp = fd;
Packit Service 97d2fb
  *eblp = ebl;
Packit Service 97d2fb
  return elf;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	error (2, 0,
Packit Service 97d2fb
	       gettext ("cannot get section header of section %zu: %s"),
Packit Service 97d2fb
	       elf_ndxscn (scn), elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      if ((shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
Packit Service 97d2fb
	  || shdr->sh_link != scnndx)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *data = elf_getdata (scn, NULL);
Packit Service 97d2fb
      if (data == NULL)
Packit Service 97d2fb
	error (2, 0,
Packit Service 97d2fb
	       gettext ("cannot get content of section %zu: %s"),
Packit Service 97d2fb
	       elf_ndxscn (scn), elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr->sh_type == SHT_REL && shdr->sh_entsize != 0)
Packit Service 97d2fb
	for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
Packit Service 97d2fb
	     ++ndx)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    GElf_Rel rel_mem;
Packit Service 97d2fb
	    GElf_Rel *rel = gelf_getrel (data, ndx, &rel_mem);
Packit Service 97d2fb
	    if (rel == NULL)
Packit Service 97d2fb
	      error (2, 0, gettext ("cannot get relocation: %s"),
Packit Service 97d2fb
		     elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
	    if ((int) GELF_R_SYM (rel->r_info) == symndx
Packit Service 97d2fb
		&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
Packit Service 97d2fb
	      return true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      else if (shdr->sh_entsize != 0)
Packit Service 97d2fb
	for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
Packit Service 97d2fb
	     ++ndx)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    GElf_Rela rela_mem;
Packit Service 97d2fb
	    GElf_Rela *rela = gelf_getrela (data, ndx, &rela_mem);
Packit Service 97d2fb
	    if (rela == NULL)
Packit Service 97d2fb
	      error (2, 0, gettext ("cannot get relocation: %s"),
Packit Service 97d2fb
		     elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
	    if ((int) GELF_R_SYM (rela->r_info) == symndx
Packit Service 97d2fb
		&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
Packit Service 97d2fb
	      return true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
regioncompare (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const struct region *r1 = (const struct region *) p1;
Packit Service 97d2fb
  const struct region *r2 = (const struct region *) p2;
Packit Service 97d2fb
Packit Service 97d2fb
  if (r1->from < r2->from)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
  return 1;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_Elf32_Word (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const Elf32_Word *w1 = p1;
Packit Service 97d2fb
  const Elf32_Word *w2 = p2;
Packit Service 97d2fb
  return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_Elf64_Xword (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const Elf64_Xword *w1 = p1;
Packit Service 97d2fb
  const Elf64_Xword *w2 = p2;
Packit Service 97d2fb
  return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
hash_content_equivalent (size_t entsize, Elf_Data *data1, Elf_Data *data2)
Packit Service 97d2fb
{
Packit Service 97d2fb
#define CHECK_HASH(Hash_Word)						      \
Packit Service 97d2fb
  {									      \
Packit Service 97d2fb
    const Hash_Word *const hash1 = data1->d_buf;			      \
Packit Service 97d2fb
    const Hash_Word *const hash2 = data2->d_buf;			      \
Packit Service 97d2fb
    const size_t nbucket = hash1[0];					      \
Packit Service 97d2fb
    const size_t nchain = hash1[1];					      \
Packit Service 97d2fb
    if (data1->d_size != (2 + nbucket + nchain) * sizeof hash1[0]	      \
Packit Service 97d2fb
	|| hash2[0] != nbucket || hash2[1] != nchain)			      \
Packit Service 97d2fb
      return false;							      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
    const Hash_Word *const bucket1 = &hash1[2];				      \
Packit Service 97d2fb
    const Hash_Word *const chain1 = &bucket1[nbucket];			      \
Packit Service 97d2fb
    const Hash_Word *const bucket2 = &hash2[2];				      \
Packit Service 97d2fb
    const Hash_Word *const chain2 = &bucket2[nbucket];			      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
    bool chain_ok[nchain];						      \
Packit Service 97d2fb
    Hash_Word temp1[nchain - 1];					      \
Packit Service 97d2fb
    Hash_Word temp2[nchain - 1];					      \
Packit Service 97d2fb
    memset (chain_ok, 0, sizeof chain_ok);				      \
Packit Service 97d2fb
    for (size_t i = 0; i < nbucket; ++i)				      \
Packit Service 97d2fb
      {									      \
Packit Service 97d2fb
	if (bucket1[i] >= nchain || bucket2[i] >= nchain)		      \
Packit Service 97d2fb
	  return false;							      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	size_t b1 = 0;							      \
Packit Service 97d2fb
	for (size_t p = bucket1[i]; p != STN_UNDEF; p = chain1[p])	      \
Packit Service 97d2fb
	  if (p >= nchain || b1 >= nchain - 1)				      \
Packit Service 97d2fb
	    return false;						      \
Packit Service 97d2fb
	  else								      \
Packit Service 97d2fb
	    temp1[b1++] = p;						      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	size_t b2 = 0;							      \
Packit Service 97d2fb
	for (size_t p = bucket2[i]; p != STN_UNDEF; p = chain2[p])	      \
Packit Service 97d2fb
	  if (p >= nchain || b2 >= nchain - 1)				      \
Packit Service 97d2fb
	    return false;						      \
Packit Service 97d2fb
	  else								      \
Packit Service 97d2fb
	    temp2[b2++] = p;						      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	if (b1 != b2)							      \
Packit Service 97d2fb
	  return false;							      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	qsort (temp1, b1, sizeof temp1[0], compare_##Hash_Word);	      \
Packit Service 97d2fb
	qsort (temp2, b2, sizeof temp2[0], compare_##Hash_Word);	      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	for (b1 = 0; b1 < b2; ++b1)					      \
Packit Service 97d2fb
	  if (temp1[b1] != temp2[b1])					      \
Packit Service 97d2fb
	    return false;						      \
Packit Service 97d2fb
	  else								      \
Packit Service 97d2fb
	    chain_ok[temp1[b1]] = true;					      \
Packit Service 97d2fb
      }									      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
    for (size_t i = 0; i < nchain; ++i)					      \
Packit Service 97d2fb
      if (!chain_ok[i] && chain1[i] != chain2[i])			      \
Packit Service 97d2fb
	return false;							      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
    return true;							      \
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  switch (entsize)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 4:
Packit Service 97d2fb
      CHECK_HASH (Elf32_Word);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 8:
Packit Service 97d2fb
      CHECK_HASH (Elf64_Xword);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#include "debugpred.h"