1 /* Compare relevant content of two ELF files.
2 Copyright (C) 2005-2012 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2005.
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.
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.
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/>. */
37 #include "../libelf/elf-knowledge.h"
38 #include "../libebl/libeblP.h"
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);
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;
51 /* Bug report address. */
52 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
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
59 /* Definitions of arguments for argp functions. */
60 static const struct argp_option options[] =
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 },
72 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
73 { NULL, 0, NULL, 0, NULL, 0 }
76 /* Short description of program. */
77 static const char doc[] = N_("\
78 Compare relevant parts of two ELF files for equality.");
80 /* Strings for arguments in help texts. */
81 static const char args_doc[] = N_("FILE1 FILE2");
83 /* Prototype for option handler. */
84 static error_t parse_opt (int key, char *arg, struct argp_state *state);
86 /* Data structure to communicate with argp functions. */
87 static struct argp argp =
89 options, parse_opt, args_doc, doc, NULL, NULL, NULL
93 /* How to treat gaps in loadable segments. */
101 /* Structure to hold information about used regions. */
109 /* Nonzero if only exit status is wanted. */
112 /* True iff multiple differences should be output. */
115 /* True iff SHT_HASH treatment should be generous. */
116 static bool hash_inexact;
118 /* True iff build ID notes should be ignored. */
119 static bool ignore_build_id;
121 static bool hash_content_equivalent (size_t entsize, Elf_Data *, Elf_Data *);
125 main (int argc, char *argv[])
128 (void) setlocale (LC_ALL, "");
130 /* Make sure the message catalog can be found. */
131 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
133 /* Initialize the message catalog. */
134 (void) textdomain (PACKAGE_TARNAME);
136 /* Parse and process arguments. */
138 (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
140 /* We expect exactly two non-option parameters. */
141 if (unlikely (remaining + 2 != argc))
143 fputs (gettext ("Invalid number of parameters.\n"), stderr);
144 argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
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
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.
159 elf_version (EV_CURRENT);
161 const char *const fname1 = argv[remaining];
164 Elf *elf1 = open_file (fname1, &fd1, &ebl1);
166 const char *const fname2 = argv[remaining + 1];
169 Elf *elf2 = open_file (fname2, &fd2, &ebl2);
172 GElf_Ehdr *ehdr1 = gelf_getehdr (elf1, &ehdr1_mem);
174 error (2, 0, gettext ("cannot get ELF header of '%s': %s"),
175 fname1, elf_errmsg (-1));
177 GElf_Ehdr *ehdr2 = gelf_getehdr (elf2, &ehdr2_mem);
179 error (2, 0, gettext ("cannot get ELF header of '%s': %s"),
180 fname2, elf_errmsg (-1));
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))
205 error (0, 0, gettext ("%s %s diff: ELF header"), fname1, fname2);
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))
220 error (0, 0, gettext ("%s %s diff: section count"), fname1, fname2);
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))
235 error (0, 0, gettext ("%s %s diff: program header count"),
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;
250 const char *sname1 = NULL;
253 scn1 = elf_nextscn (elf1, scn1);
254 shdr1 = gelf_getshdr (scn1, &shdr1_mem);
256 sname1 = elf_strptr (elf1, ehdr1->e_shstrndx, shdr1->sh_name);
259 && ebl_section_strip_p (ebl1, ehdr1, shdr1, sname1, true, false));
263 const char *sname2 = NULL;
266 scn2 = elf_nextscn (elf2, scn2);
267 shdr2 = gelf_getshdr (scn2, &shdr2_mem);
269 sname2 = elf_strptr (elf2, ehdr2->e_shstrndx, shdr2->sh_name);
272 && ebl_section_strip_p (ebl2, ehdr2, shdr2, sname2, true, false));
274 if (scn1 == NULL || scn2 == NULL)
277 if (gaps != gaps_ignore && (shdr1->sh_flags & SHF_ALLOC) != 0)
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;
288 /* Compare the headers. We allow the name to be at a different
290 if (unlikely (strcmp (sname1, sname2) != 0))
292 error (0, 0, gettext ("%s %s differ: section [%zu], [%zu] name"),
293 fname1, fname2, elf_ndxscn (scn1), elf_ndxscn (scn2));
297 /* We ignore certain sections. */
298 if (strcmp (sname1, ".gnu_debuglink") == 0
299 || strcmp (sname1, ".gnu.prelink_undo") == 0)
302 if (shdr1->sh_type != shdr2->sh_type
303 // XXX Any flags which should be ignored?
304 || shdr1->sh_flags != shdr2->sh_flags
305 || shdr1->sh_addr != shdr2->sh_addr
306 || (shdr1->sh_offset != shdr2->sh_offset
307 && (shdr1->sh_flags & SHF_ALLOC)
308 && ehdr1->e_type != ET_REL)
309 || shdr1->sh_size != shdr2->sh_size
310 || shdr1->sh_link != shdr2->sh_link
311 || shdr1->sh_info != shdr2->sh_info
312 || shdr1->sh_addralign != shdr2->sh_addralign
313 || shdr1->sh_entsize != shdr2->sh_entsize)
315 error (0, 0, gettext ("%s %s differ: section [%zu] '%s' header"),
316 fname1, fname2, elf_ndxscn (scn1), sname1);
320 Elf_Data *data1 = elf_getdata (scn1, NULL);
323 gettext ("cannot get content of section %zu in '%s': %s"),
324 elf_ndxscn (scn1), fname1, elf_errmsg (-1));
326 Elf_Data *data2 = elf_getdata (scn2, NULL);
329 gettext ("cannot get content of section %zu in '%s': %s"),
330 elf_ndxscn (scn2), fname2, elf_errmsg (-1));
332 switch (shdr1->sh_type)
336 /* Iterate over the symbol table. We ignore the st_size
337 value of undefined symbols. */
338 for (int ndx = 0; ndx < (int) (shdr1->sh_size / shdr1->sh_entsize);
342 GElf_Sym *sym1 = gelf_getsym (data1, ndx, &sym1_mem);
345 gettext ("cannot get symbol in '%s': %s"),
346 fname1, elf_errmsg (-1));
348 GElf_Sym *sym2 = gelf_getsym (data2, ndx, &sym2_mem);
351 gettext ("cannot get symbol in '%s': %s"),
352 fname2, elf_errmsg (-1));
354 const char *name1 = elf_strptr (elf1, shdr1->sh_link,
356 const char *name2 = elf_strptr (elf2, shdr2->sh_link,
358 if (unlikely (strcmp (name1, name2) != 0
359 || sym1->st_value != sym2->st_value
360 || (sym1->st_size != sym2->st_size
361 && sym1->st_shndx != SHN_UNDEF)
362 || sym1->st_info != sym2->st_info
363 || sym1->st_other != sym2->st_other
364 || sym1->st_shndx != sym1->st_shndx))
366 // XXX Do we want to allow reordered symbol tables?
370 if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
372 gettext ("%s %s differ: symbol table [%zu]"),
373 fname1, fname2, elf_ndxscn (scn1));
375 error (0, 0, gettext ("\
376 %s %s differ: symbol table [%zu,%zu]"),
377 fname1, fname2, elf_ndxscn (scn1),
384 if (sym1->st_shndx == SHN_UNDEF
385 && sym1->st_size != sym2->st_size)
387 /* The size of the symbol in the object defining it
388 might have changed. That is OK unless the symbol
389 is used in a copy relocation. Look over the
390 sections in both files and determine which
391 relocation section uses this symbol table
392 section. Then look through the relocations to
393 see whether any copy relocation references this
395 if (search_for_copy_reloc (ebl1, elf_ndxscn (scn1), ndx)
396 || search_for_copy_reloc (ebl2, elf_ndxscn (scn2), ndx))
397 goto symtab_mismatch;
403 /* Parse the note format and compare the notes themselves. */
412 while (off1 < data1->d_size
413 && (off1 = gelf_getnote (data1, off1, ¬e1,
414 &name_offset, &desc_offset)) > 0)
416 const char *name1 = data1->d_buf + name_offset;
417 const void *desc1 = data1->d_buf + desc_offset;
418 if (off2 >= data2->d_size)
421 error (0, 0, gettext ("\
422 %s %s differ: section [%zu] '%s' number of notes"),
423 fname1, fname2, elf_ndxscn (scn1), sname1);
426 off2 = gelf_getnote (data2, off2, ¬e2,
427 &name_offset, &desc_offset);
429 error (2, 0, gettext ("\
430 cannot read note section [%zu] '%s' in '%s': %s"),
431 elf_ndxscn (scn2), sname2, fname2, elf_errmsg (-1));
432 const char *name2 = data2->d_buf + name_offset;
433 const void *desc2 = data2->d_buf + desc_offset;
435 if (note1.n_namesz != note2.n_namesz
436 || memcmp (name1, name2, note1.n_namesz))
439 error (0, 0, gettext ("\
440 %s %s differ: section [%zu] '%s' note name"),
441 fname1, fname2, elf_ndxscn (scn1), sname1);
444 if (note1.n_type != note2.n_type)
447 error (0, 0, gettext ("\
448 %s %s differ: section [%zu] '%s' note '%s' type"),
449 fname1, fname2, elf_ndxscn (scn1), sname1, name1);
452 if (note1.n_descsz != note2.n_descsz
453 || memcmp (desc1, desc2, note1.n_descsz))
455 if (note1.n_type == NT_GNU_BUILD_ID
456 && note1.n_namesz == sizeof "GNU"
457 && !memcmp (name1, "GNU", sizeof "GNU"))
459 if (note1.n_descsz != note2.n_descsz)
462 error (0, 0, gettext ("\
463 %s %s differ: build ID length"),
467 else if (! ignore_build_id)
470 error (0, 0, gettext ("\
471 %s %s differ: build ID content"),
479 error (0, 0, gettext ("\
480 %s %s differ: section [%zu] '%s' note '%s' content"),
481 fname1, fname2, elf_ndxscn (scn1), sname1,
487 if (off2 < data2->d_size)
490 error (0, 0, gettext ("\
491 %s %s differ: section [%zu] '%s' number of notes"),
492 fname1, fname2, elf_ndxscn (scn1), sname1);
499 /* Compare the section content byte for byte. */
500 assert (shdr1->sh_type == SHT_NOBITS
501 || (data1->d_buf != NULL || data1->d_size == 0));
502 assert (shdr2->sh_type == SHT_NOBITS
503 || (data2->d_buf != NULL || data1->d_size == 0));
505 if (unlikely (data1->d_size != data2->d_size
506 || (shdr1->sh_type != SHT_NOBITS
507 && memcmp (data1->d_buf, data2->d_buf,
508 data1->d_size) != 0)))
511 && shdr1->sh_type == SHT_HASH
512 && data1->d_size == data2->d_size
513 && hash_content_equivalent (shdr1->sh_entsize, data1, data2))
518 if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
519 error (0, 0, gettext ("\
520 %s %s differ: section [%zu] '%s' content"),
521 fname1, fname2, elf_ndxscn (scn1), sname1);
523 error (0, 0, gettext ("\
524 %s %s differ: section [%zu,%zu] '%s' content"),
525 fname1, fname2, elf_ndxscn (scn1),
526 elf_ndxscn (scn2), sname1);
534 if (unlikely (scn1 != scn2))
538 gettext ("%s %s differ: unequal amount of important sections"),
543 /* We we look at gaps, create artificial ones for the parts of the
544 program which we are not in sections. */
545 struct region ehdr_region;
546 struct region phdr_region;
547 if (gaps != gaps_ignore)
549 ehdr_region.from = 0;
550 ehdr_region.to = ehdr1->e_ehsize;
551 ehdr_region.next = &phdr_region;
553 phdr_region.from = ehdr1->e_phoff;
554 phdr_region.to = ehdr1->e_phoff + phnum1 * ehdr1->e_phentsize;
555 phdr_region.next = regions;
557 regions = &ehdr_region;
561 /* If we need to look at the gaps we need access to the file data. */
566 struct region *regionsarr = alloca (nregions * sizeof (struct region));
567 if (gaps != gaps_ignore)
569 raw1 = elf_rawfile (elf1, &size1);
571 error (2, 0, gettext ("cannot load data of '%s': %s"),
572 fname1, elf_errmsg (-1));
574 raw2 = elf_rawfile (elf2, &size2);
576 error (2, 0, gettext ("cannot load data of '%s': %s"),
577 fname2, elf_errmsg (-1));
579 for (size_t cnt = 0; cnt < nregions; ++cnt)
581 regionsarr[cnt] = *regions;
582 regions = regions->next;
585 qsort (regionsarr, nregions, sizeof (regionsarr[0]), regioncompare);
588 /* Compare the program header tables. */
589 for (unsigned int ndx = 0; ndx < phnum1; ++ndx)
592 GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem);
595 gettext ("cannot get program header entry %d of '%s': %s"),
596 ndx, fname1, elf_errmsg (-1));
598 GElf_Phdr *phdr2 = gelf_getphdr (elf2, ndx, &phdr2_mem);
601 gettext ("cannot get program header entry %d of '%s': %s"),
602 ndx, fname2, elf_errmsg (-1));
604 if (unlikely (memcmp (phdr1, phdr2, sizeof (GElf_Phdr)) != 0))
607 error (0, 0, gettext ("%s %s differ: program header %d"),
608 fname1, fname2, ndx);
612 if (gaps != gaps_ignore && phdr1->p_type == PT_LOAD)
615 while (cnt < nregions && regionsarr[cnt].to < phdr1->p_offset)
618 GElf_Off last = phdr1->p_offset;
619 GElf_Off end = phdr1->p_offset + phdr1->p_filesz;
620 while (cnt < nregions && regionsarr[cnt].from < end)
622 if (last < regionsarr[cnt].from)
624 /* Compare the [LAST,FROM) region. */
625 assert (gaps == gaps_match);
626 if (unlikely (memcmp (raw1 + last, raw2 + last,
627 regionsarr[cnt].from - last) != 0))
631 error (0, 0, gettext ("%s %s differ: gap"),
638 last = regionsarr[cnt].to;
642 if (cnt == nregions && last < end)
657 /* Print the version information. */
659 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
661 fprintf (stream, "elfcmp (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
662 fprintf (stream, gettext ("\
663 Copyright (C) %s Red Hat, Inc.\n\
664 This is free software; see the source for copying conditions. There is NO\n\
665 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
667 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
671 /* Handle program arguments. */
673 parse_opt (int key, char *arg,
674 struct argp_state *state __attribute__ ((unused)))
687 if (strcasecmp (arg, "ignore") == 0)
689 else if (likely (strcasecmp (arg, "match") == 0))
694 gettext ("Invalid value '%s' for --gaps parameter."),
696 argp_help (&argp, stderr, ARGP_HELP_SEE,
697 program_invocation_short_name);
702 case OPT_HASH_INEXACT:
706 case OPT_IGNORE_BUILD_ID:
707 ignore_build_id = true;
711 return ARGP_ERR_UNKNOWN;
718 open_file (const char *fname, int *fdp, Ebl **eblp)
720 int fd = open (fname, O_RDONLY);
721 if (unlikely (fd == -1))
722 error (2, errno, gettext ("cannot open '%s'"), fname);
723 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
726 gettext ("cannot create ELF descriptor for '%s': %s"),
727 fname, elf_errmsg (-1));
728 Ebl *ebl = ebl_openbackend (elf);
731 gettext ("cannot create EBL descriptor for '%s'"), fname);
740 search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx)
743 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
746 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
749 gettext ("cannot get section header of section %zu: %s"),
750 elf_ndxscn (scn), elf_errmsg (-1));
752 if ((shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
753 || shdr->sh_link != scnndx)
756 Elf_Data *data = elf_getdata (scn, NULL);
759 gettext ("cannot get content of section %zu: %s"),
760 elf_ndxscn (scn), elf_errmsg (-1));
762 if (shdr->sh_type == SHT_REL)
763 for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
767 GElf_Rel *rel = gelf_getrel (data, ndx, &rel_mem);
769 error (2, 0, gettext ("cannot get relocation: %s"),
772 if ((int) GELF_R_SYM (rel->r_info) == symndx
773 && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
777 for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
781 GElf_Rela *rela = gelf_getrela (data, ndx, &rela_mem);
783 error (2, 0, gettext ("cannot get relocation: %s"),
786 if ((int) GELF_R_SYM (rela->r_info) == symndx
787 && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
797 regioncompare (const void *p1, const void *p2)
799 const struct region *r1 = (const struct region *) p1;
800 const struct region *r2 = (const struct region *) p2;
802 if (r1->from < r2->from)
809 compare_Elf32_Word (const void *p1, const void *p2)
811 const Elf32_Word *w1 = p1;
812 const Elf32_Word *w2 = p2;
813 assert (sizeof (int) >= sizeof (*w1));
814 return (int) *w1 - (int) *w2;
818 compare_Elf64_Xword (const void *p1, const void *p2)
820 const Elf64_Xword *w1 = p1;
821 const Elf64_Xword *w2 = p2;
822 return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
826 hash_content_equivalent (size_t entsize, Elf_Data *data1, Elf_Data *data2)
828 #define CHECK_HASH(Hash_Word) \
830 const Hash_Word *const hash1 = data1->d_buf; \
831 const Hash_Word *const hash2 = data2->d_buf; \
832 const size_t nbucket = hash1[0]; \
833 const size_t nchain = hash1[1]; \
834 if (data1->d_size != (2 + nbucket + nchain) * sizeof hash1[0] \
835 || hash2[0] != nbucket || hash2[1] != nchain) \
838 const Hash_Word *const bucket1 = &hash1[2]; \
839 const Hash_Word *const chain1 = &bucket1[nbucket]; \
840 const Hash_Word *const bucket2 = &hash2[2]; \
841 const Hash_Word *const chain2 = &bucket2[nbucket]; \
843 bool chain_ok[nchain]; \
844 Hash_Word temp1[nchain - 1]; \
845 Hash_Word temp2[nchain - 1]; \
846 memset (chain_ok, 0, sizeof chain_ok); \
847 for (size_t i = 0; i < nbucket; ++i) \
849 if (bucket1[i] >= nchain || bucket2[i] >= nchain) \
853 for (size_t p = bucket1[i]; p != STN_UNDEF; p = chain1[p]) \
854 if (p >= nchain || b1 >= nchain - 1) \
860 for (size_t p = bucket2[i]; p != STN_UNDEF; p = chain2[p]) \
861 if (p >= nchain || b2 >= nchain - 1) \
869 qsort (temp1, b1, sizeof temp1[0], compare_##Hash_Word); \
870 qsort (temp2, b2, sizeof temp2[0], compare_##Hash_Word); \
872 for (b1 = 0; b1 < b2; ++b1) \
873 if (temp1[b1] != temp2[b1]) \
876 chain_ok[temp1[b1]] = true; \
879 for (size_t i = 0; i < nchain; ++i) \
880 if (!chain_ok[i] && chain1[i] != chain2[i]) \
889 CHECK_HASH (Elf32_Word);
892 CHECK_HASH (Elf64_Xword);
900 #include "debugpred.h"