LCOV - code coverage report
Current view: top level - src - elfcmp.c (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 174 377 46.2 %
Date: 2023-08-29 13:46:25 Functions: 5 8 62.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 145 428 33.9 %

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

Generated by: LCOV version 1.16