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