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