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