|
Packit Service |
97d2fb |
/* Compare relevant content of two ELF files.
|
|
Packit Service |
97d2fb |
Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc.
|
|
Packit Service |
97d2fb |
This file is part of elfutils.
|
|
Packit Service |
97d2fb |
Written by Ulrich Drepper <drepper@redhat.com>, 2005.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
This file is free software; you can redistribute it and/or modify
|
|
Packit Service |
97d2fb |
it under the terms of the GNU General Public License as published by
|
|
Packit Service |
97d2fb |
the Free Software Foundation; either version 3 of the License, or
|
|
Packit Service |
97d2fb |
(at your option) any later version.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
elfutils is distributed in the hope that it will be useful, but
|
|
Packit Service |
97d2fb |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
97d2fb |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
97d2fb |
GNU General Public License for more details.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
You should have received a copy of the GNU General Public License
|
|
Packit Service |
97d2fb |
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
97d2fb |
# include <config.h>
|
|
Packit Service |
97d2fb |
#endif
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include <argp.h>
|
|
Packit Service |
97d2fb |
#include <assert.h>
|
|
Packit Service |
97d2fb |
#include <errno.h>
|
|
Packit Service |
97d2fb |
#include <fcntl.h>
|
|
Packit Service |
97d2fb |
#include <locale.h>
|
|
Packit Service |
97d2fb |
#include <libintl.h>
|
|
Packit Service |
97d2fb |
#include <stdbool.h>
|
|
Packit Service |
97d2fb |
#include <stdio.h>
|
|
Packit Service |
97d2fb |
#include <stdlib.h>
|
|
Packit Service |
97d2fb |
#include <string.h>
|
|
Packit Service |
97d2fb |
#include <unistd.h>
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include <printversion.h>
|
|
Packit Service |
97d2fb |
#include "../libelf/elf-knowledge.h"
|
|
Packit Service |
97d2fb |
#include "../libebl/libeblP.h"
|
|
Packit Service |
97d2fb |
#include "system.h"
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Prototypes of local functions. */
|
|
Packit Service |
97d2fb |
static Elf *open_file (const char *fname, int *fdp, Ebl **eblp);
|
|
Packit Service |
97d2fb |
static bool search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx);
|
|
Packit Service |
97d2fb |
static int regioncompare (const void *p1, const void *p2);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Name and version of program. */
|
|
Packit Service |
97d2fb |
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Bug report address. */
|
|
Packit Service |
97d2fb |
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Values for the parameters which have no short form. */
|
|
Packit Service |
97d2fb |
#define OPT_GAPS 0x100
|
|
Packit Service |
97d2fb |
#define OPT_HASH_INEXACT 0x101
|
|
Packit Service |
97d2fb |
#define OPT_IGNORE_BUILD_ID 0x102
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Definitions of arguments for argp functions. */
|
|
Packit Service |
97d2fb |
static const struct argp_option options[] =
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
{ NULL, 0, NULL, 0, N_("Control options:"), 0 },
|
|
Packit Service |
97d2fb |
{ "verbose", 'l', NULL, 0,
|
|
Packit Service |
97d2fb |
N_("Output all differences, not just the first"), 0 },
|
|
Packit Service |
97d2fb |
{ "gaps", OPT_GAPS, "ACTION", 0, N_("Control treatment of gaps in loadable segments [ignore|match] (default: ignore)"), 0 },
|
|
Packit Service |
97d2fb |
{ "hash-inexact", OPT_HASH_INEXACT, NULL, 0,
|
|
Packit Service |
97d2fb |
N_("Ignore permutation of buckets in SHT_HASH section"), 0 },
|
|
Packit Service |
97d2fb |
{ "ignore-build-id", OPT_IGNORE_BUILD_ID, NULL, 0,
|
|
Packit Service |
97d2fb |
N_("Ignore differences in build ID"), 0 },
|
|
Packit Service |
97d2fb |
{ "quiet", 'q', NULL, 0, N_("Output nothing; yield exit status only"), 0 },
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
{ NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
|
|
Packit Service |
97d2fb |
{ NULL, 0, NULL, 0, NULL, 0 }
|
|
Packit Service |
97d2fb |
};
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Short description of program. */
|
|
Packit Service |
97d2fb |
static const char doc[] = N_("\
|
|
Packit Service |
97d2fb |
Compare relevant parts of two ELF files for equality.");
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Strings for arguments in help texts. */
|
|
Packit Service |
97d2fb |
static const char args_doc[] = N_("FILE1 FILE2");
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Prototype for option handler. */
|
|
Packit Service |
97d2fb |
static error_t parse_opt (int key, char *arg, struct argp_state *state);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Data structure to communicate with argp functions. */
|
|
Packit Service |
97d2fb |
static struct argp argp =
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
options, parse_opt, args_doc, doc, NULL, NULL, NULL
|
|
Packit Service |
97d2fb |
};
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* How to treat gaps in loadable segments. */
|
|
Packit Service |
97d2fb |
static enum
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
gaps_ignore = 0,
|
|
Packit Service |
97d2fb |
gaps_match
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
gaps;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Structure to hold information about used regions. */
|
|
Packit Service |
97d2fb |
struct region
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Addr from;
|
|
Packit Service |
97d2fb |
GElf_Addr to;
|
|
Packit Service |
97d2fb |
struct region *next;
|
|
Packit Service |
97d2fb |
};
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Nonzero if only exit status is wanted. */
|
|
Packit Service |
97d2fb |
static bool quiet;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* True iff multiple differences should be output. */
|
|
Packit Service |
97d2fb |
static bool verbose;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* True iff SHT_HASH treatment should be generous. */
|
|
Packit Service |
97d2fb |
static bool hash_inexact;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* True iff build ID notes should be ignored. */
|
|
Packit Service |
97d2fb |
static bool ignore_build_id;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static bool hash_content_equivalent (size_t entsize, Elf_Data *, Elf_Data *);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
int
|
|
Packit Service |
97d2fb |
main (int argc, char *argv[])
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Set locale. */
|
|
Packit Service |
97d2fb |
(void) setlocale (LC_ALL, "");
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Make sure the message catalog can be found. */
|
|
Packit Service |
97d2fb |
(void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Initialize the message catalog. */
|
|
Packit Service |
97d2fb |
(void) textdomain (PACKAGE_TARNAME);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Parse and process arguments. */
|
|
Packit Service |
97d2fb |
int remaining;
|
|
Packit Service |
97d2fb |
(void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* We expect exactly two non-option parameters. */
|
|
Packit Service |
97d2fb |
if (unlikely (remaining + 2 != argc))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
fputs (gettext ("Invalid number of parameters.\n"), stderr);
|
|
Packit Service |
97d2fb |
argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
|
|
Packit Service |
97d2fb |
exit (1);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (quiet)
|
|
Packit Service |
97d2fb |
verbose = false;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Comparing the files is done in two phases:
|
|
Packit Service |
97d2fb |
1. compare all sections. Sections which are irrelevant (i.e., if
|
|
Packit Service |
97d2fb |
strip would remove them) are ignored. Some section types are
|
|
Packit Service |
97d2fb |
handled special.
|
|
Packit Service |
97d2fb |
2. all parts of the loadable segments which are not parts of any
|
|
Packit Service |
97d2fb |
section is compared according to the rules of the --gaps option.
|
|
Packit Service |
97d2fb |
*/
|
|
Packit Service |
97d2fb |
int result = 0;
|
|
Packit Service |
97d2fb |
elf_version (EV_CURRENT);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
const char *const fname1 = argv[remaining];
|
|
Packit Service |
97d2fb |
int fd1;
|
|
Packit Service |
97d2fb |
Ebl *ebl1;
|
|
Packit Service |
97d2fb |
Elf *elf1 = open_file (fname1, &fd1, &ebl1);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
const char *const fname2 = argv[remaining + 1];
|
|
Packit Service |
97d2fb |
int fd2;
|
|
Packit Service |
97d2fb |
Ebl *ebl2;
|
|
Packit Service |
97d2fb |
Elf *elf2 = open_file (fname2, &fd2, &ebl2);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
GElf_Ehdr ehdr1_mem;
|
|
Packit Service |
97d2fb |
GElf_Ehdr *ehdr1 = gelf_getehdr (elf1, &ehdr1_mem);
|
|
Packit Service |
97d2fb |
if (ehdr1 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get ELF header of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
GElf_Ehdr ehdr2_mem;
|
|
Packit Service |
97d2fb |
GElf_Ehdr *ehdr2 = gelf_getehdr (elf2, &ehdr2_mem);
|
|
Packit Service |
97d2fb |
if (ehdr2 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get ELF header of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#define DIFFERENCE \
|
|
Packit Service |
97d2fb |
do \
|
|
Packit Service |
97d2fb |
{ \
|
|
Packit Service |
97d2fb |
result = 1; \
|
|
Packit Service |
97d2fb |
if (! verbose) \
|
|
Packit Service |
97d2fb |
goto out; \
|
|
Packit Service |
97d2fb |
} \
|
|
Packit Service |
97d2fb |
while (0)
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Compare the ELF headers. */
|
|
Packit Service |
97d2fb |
if (unlikely (memcmp (ehdr1->e_ident, ehdr2->e_ident, EI_NIDENT) != 0
|
|
Packit Service |
97d2fb |
|| ehdr1->e_type != ehdr2->e_type
|
|
Packit Service |
97d2fb |
|| ehdr1->e_machine != ehdr2->e_machine
|
|
Packit Service |
97d2fb |
|| ehdr1->e_version != ehdr2->e_version
|
|
Packit Service |
97d2fb |
|| ehdr1->e_entry != ehdr2->e_entry
|
|
Packit Service |
97d2fb |
|| ehdr1->e_phoff != ehdr2->e_phoff
|
|
Packit Service |
97d2fb |
|| ehdr1->e_flags != ehdr2->e_flags
|
|
Packit Service |
97d2fb |
|| ehdr1->e_ehsize != ehdr2->e_ehsize
|
|
Packit Service |
97d2fb |
|| ehdr1->e_phentsize != ehdr2->e_phentsize
|
|
Packit Service |
97d2fb |
|| ehdr1->e_phnum != ehdr2->e_phnum
|
|
Packit Service |
97d2fb |
|| ehdr1->e_shentsize != ehdr2->e_shentsize))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s diff: ELF header"), fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t shnum1;
|
|
Packit Service |
97d2fb |
size_t shnum2;
|
|
Packit Service |
97d2fb |
if (unlikely (elf_getshdrnum (elf1, &shnum1) != 0))
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get section count of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
if (unlikely (elf_getshdrnum (elf2, &shnum2) != 0))
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get section count of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
if (unlikely (shnum1 != shnum2))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s diff: section count"), fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t phnum1;
|
|
Packit Service |
97d2fb |
size_t phnum2;
|
|
Packit Service |
97d2fb |
if (unlikely (elf_getphdrnum (elf1, &phnum1) != 0))
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get program header count of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
if (unlikely (elf_getphdrnum (elf2, &phnum2) != 0))
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get program header count of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
if (unlikely (phnum1 != phnum2))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s diff: program header count"),
|
|
Packit Service |
97d2fb |
fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t shstrndx1;
|
|
Packit Service |
97d2fb |
size_t shstrndx2;
|
|
Packit Service |
97d2fb |
if (elf_getshdrstrndx (elf1, &shstrndx1) != 0)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get hdrstrndx of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
if (elf_getshdrstrndx (elf2, &shstrndx2) != 0)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get hdrstrndx of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
if (shstrndx1 != shstrndx2)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s diff: shdr string index"),
|
|
Packit Service |
97d2fb |
fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Iterate over all sections. We expect the sections in the two
|
|
Packit Service |
97d2fb |
files to match exactly. */
|
|
Packit Service |
97d2fb |
Elf_Scn *scn1 = NULL;
|
|
Packit Service |
97d2fb |
Elf_Scn *scn2 = NULL;
|
|
Packit Service |
97d2fb |
struct region *regions = NULL;
|
|
Packit Service |
97d2fb |
size_t nregions = 0;
|
|
Packit Service |
97d2fb |
while (1)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Shdr shdr1_mem;
|
|
Packit Service |
97d2fb |
GElf_Shdr *shdr1;
|
|
Packit Service |
97d2fb |
const char *sname1 = NULL;
|
|
Packit Service |
97d2fb |
do
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
scn1 = elf_nextscn (elf1, scn1);
|
|
Packit Service |
97d2fb |
shdr1 = gelf_getshdr (scn1, &shdr1_mem);
|
|
Packit Service |
97d2fb |
if (shdr1 != NULL)
|
|
Packit Service |
97d2fb |
sname1 = elf_strptr (elf1, shstrndx1, shdr1->sh_name);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
while (scn1 != NULL && shdr1 != NULL
|
|
Packit Service |
97d2fb |
&& ebl_section_strip_p (ebl1, shdr1, sname1, true, false));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
GElf_Shdr shdr2_mem;
|
|
Packit Service |
97d2fb |
GElf_Shdr *shdr2;
|
|
Packit Service |
97d2fb |
const char *sname2 = NULL;
|
|
Packit Service |
97d2fb |
do
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
scn2 = elf_nextscn (elf2, scn2);
|
|
Packit Service |
97d2fb |
shdr2 = gelf_getshdr (scn2, &shdr2_mem);
|
|
Packit Service |
97d2fb |
if (shdr2 != NULL)
|
|
Packit Service |
97d2fb |
sname2 = elf_strptr (elf2, shstrndx2, shdr2->sh_name);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
while (scn2 != NULL && shdr2 != NULL
|
|
Packit Service |
97d2fb |
&& ebl_section_strip_p (ebl2, shdr2, sname2, true, false));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (scn1 == NULL || scn2 == NULL || shdr1 == NULL || shdr2 == NULL)
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (gaps != gaps_ignore && (shdr1->sh_flags & SHF_ALLOC) != 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct region *newp = (struct region *) alloca (sizeof (*newp));
|
|
Packit Service |
97d2fb |
newp->from = shdr1->sh_offset;
|
|
Packit Service |
97d2fb |
newp->to = shdr1->sh_offset + shdr1->sh_size;
|
|
Packit Service |
97d2fb |
newp->next = regions;
|
|
Packit Service |
97d2fb |
regions = newp;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
++nregions;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Compare the headers. We allow the name to be at a different
|
|
Packit Service |
97d2fb |
location. */
|
|
Packit Service |
97d2fb |
if (unlikely (sname1 == NULL || sname2 == NULL
|
|
Packit Service |
97d2fb |
|| strcmp (sname1, sname2) != 0))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s differ: section [%zu], [%zu] name"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), elf_ndxscn (scn2));
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* We ignore certain sections. */
|
|
Packit Service |
97d2fb |
if ((sname1 != NULL && strcmp (sname1, ".gnu_debuglink") == 0)
|
|
Packit Service |
97d2fb |
|| (sname1 != NULL && strcmp (sname1, ".gnu.prelink_undo") == 0))
|
|
Packit Service |
97d2fb |
continue;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (shdr1->sh_type != shdr2->sh_type
|
|
Packit Service |
97d2fb |
// XXX Any flags which should be ignored?
|
|
Packit Service |
97d2fb |
|| shdr1->sh_flags != shdr2->sh_flags
|
|
Packit Service |
97d2fb |
|| shdr1->sh_addr != shdr2->sh_addr
|
|
Packit Service |
97d2fb |
|| (shdr1->sh_offset != shdr2->sh_offset
|
|
Packit Service |
97d2fb |
&& (shdr1->sh_flags & SHF_ALLOC)
|
|
Packit Service |
97d2fb |
&& ehdr1->e_type != ET_REL)
|
|
Packit Service |
97d2fb |
|| shdr1->sh_size != shdr2->sh_size
|
|
Packit Service |
97d2fb |
|| shdr1->sh_link != shdr2->sh_link
|
|
Packit Service |
97d2fb |
|| shdr1->sh_info != shdr2->sh_info
|
|
Packit Service |
97d2fb |
|| shdr1->sh_addralign != shdr2->sh_addralign
|
|
Packit Service |
97d2fb |
|| shdr1->sh_entsize != shdr2->sh_entsize)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s differ: section [%zu] '%s' header"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf_Data *data1 = elf_getdata (scn1, NULL);
|
|
Packit Service |
97d2fb |
if (data1 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get content of section %zu in '%s': %s"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn1), fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf_Data *data2 = elf_getdata (scn2, NULL);
|
|
Packit Service |
97d2fb |
if (data2 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get content of section %zu in '%s': %s"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn2), fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
switch (shdr1->sh_type)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
case SHT_DYNSYM:
|
|
Packit Service |
97d2fb |
case SHT_SYMTAB:
|
|
Packit Service |
97d2fb |
if (shdr1->sh_entsize == 0)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("symbol table [%zu] in '%s' has zero sh_entsize"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn1), fname1);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Iterate over the symbol table. We ignore the st_size
|
|
Packit Service |
97d2fb |
value of undefined symbols. */
|
|
Packit Service |
97d2fb |
for (int ndx = 0; ndx < (int) (shdr1->sh_size / shdr1->sh_entsize);
|
|
Packit Service |
97d2fb |
++ndx)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Sym sym1_mem;
|
|
Packit Service |
97d2fb |
GElf_Sym *sym1 = gelf_getsym (data1, ndx, &sym1_mem);
|
|
Packit Service |
97d2fb |
if (sym1 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get symbol in '%s': %s"),
|
|
Packit Service |
97d2fb |
fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
GElf_Sym sym2_mem;
|
|
Packit Service |
97d2fb |
GElf_Sym *sym2 = gelf_getsym (data2, ndx, &sym2_mem);
|
|
Packit Service |
97d2fb |
if (sym2 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get symbol in '%s': %s"),
|
|
Packit Service |
97d2fb |
fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
const char *name1 = elf_strptr (elf1, shdr1->sh_link,
|
|
Packit Service |
97d2fb |
sym1->st_name);
|
|
Packit Service |
97d2fb |
const char *name2 = elf_strptr (elf2, shdr2->sh_link,
|
|
Packit Service |
97d2fb |
sym2->st_name);
|
|
Packit Service |
97d2fb |
if (unlikely (name1 == NULL || name2 == NULL
|
|
Packit Service |
97d2fb |
|| strcmp (name1, name2) != 0
|
|
Packit Service |
97d2fb |
|| sym1->st_value != sym2->st_value
|
|
Packit Service |
97d2fb |
|| (sym1->st_size != sym2->st_size
|
|
Packit Service |
97d2fb |
&& sym1->st_shndx != SHN_UNDEF)
|
|
Packit Service |
97d2fb |
|| sym1->st_info != sym2->st_info
|
|
Packit Service |
97d2fb |
|| sym1->st_other != sym2->st_other
|
|
Packit Service |
97d2fb |
|| sym1->st_shndx != sym2->st_shndx))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
// XXX Do we want to allow reordered symbol tables?
|
|
Packit Service |
97d2fb |
symtab_mismatch:
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
|
|
Packit Service |
97d2fb |
error (0, 0,
|
|
Packit Service |
97d2fb |
gettext ("%s %s differ: symbol table [%zu]"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1));
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: symbol table [%zu,%zu]"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn2));
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (sym1->st_shndx == SHN_UNDEF
|
|
Packit Service |
97d2fb |
&& sym1->st_size != sym2->st_size)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* The size of the symbol in the object defining it
|
|
Packit Service |
97d2fb |
might have changed. That is OK unless the symbol
|
|
Packit Service |
97d2fb |
is used in a copy relocation. Look over the
|
|
Packit Service |
97d2fb |
sections in both files and determine which
|
|
Packit Service |
97d2fb |
relocation section uses this symbol table
|
|
Packit Service |
97d2fb |
section. Then look through the relocations to
|
|
Packit Service |
97d2fb |
see whether any copy relocation references this
|
|
Packit Service |
97d2fb |
symbol. */
|
|
Packit Service |
97d2fb |
if (search_for_copy_reloc (ebl1, elf_ndxscn (scn1), ndx)
|
|
Packit Service |
97d2fb |
|| search_for_copy_reloc (ebl2, elf_ndxscn (scn2), ndx))
|
|
Packit Service |
97d2fb |
goto symtab_mismatch;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case SHT_NOTE:
|
|
Packit Service |
97d2fb |
/* Parse the note format and compare the notes themselves. */
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Nhdr note1;
|
|
Packit Service |
97d2fb |
GElf_Nhdr note2;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t off1 = 0;
|
|
Packit Service |
97d2fb |
size_t off2 = 0;
|
|
Packit Service |
97d2fb |
size_t name_offset;
|
|
Packit Service |
97d2fb |
size_t desc_offset;
|
|
Packit Service |
97d2fb |
while (off1 < data1->d_size
|
|
Packit Service |
97d2fb |
&& (off1 = gelf_getnote (data1, off1, ¬e1,
|
|
Packit Service |
97d2fb |
&name_offset, &desc_offset)) > 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
const char *name1 = (note1.n_namesz == 0
|
|
Packit Service |
97d2fb |
? "" : data1->d_buf + name_offset);
|
|
Packit Service |
97d2fb |
const void *desc1 = data1->d_buf + desc_offset;
|
|
Packit Service |
97d2fb |
if (off2 >= data2->d_size)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu] '%s' number of notes"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
off2 = gelf_getnote (data2, off2, ¬e2,
|
|
Packit Service |
97d2fb |
&name_offset, &desc_offset);
|
|
Packit Service |
97d2fb |
if (off2 == 0)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("\
|
|
Packit Service |
97d2fb |
cannot read note section [%zu] '%s' in '%s': %s"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn2), sname2, fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
const char *name2 = (note2.n_namesz == 0
|
|
Packit Service |
97d2fb |
? "" : data2->d_buf + name_offset);
|
|
Packit Service |
97d2fb |
const void *desc2 = data2->d_buf + desc_offset;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (note1.n_namesz != note2.n_namesz
|
|
Packit Service |
97d2fb |
|| memcmp (name1, name2, note1.n_namesz))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu] '%s' note name"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
if (note1.n_type != note2.n_type)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu] '%s' note '%s' type"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1, name1);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
if (note1.n_descsz != note2.n_descsz
|
|
Packit Service |
97d2fb |
|| memcmp (desc1, desc2, note1.n_descsz))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (note1.n_type == NT_GNU_BUILD_ID
|
|
Packit Service |
97d2fb |
&& note1.n_namesz == sizeof "GNU"
|
|
Packit Service |
97d2fb |
&& !memcmp (name1, "GNU", sizeof "GNU"))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (note1.n_descsz != note2.n_descsz)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: build ID length"),
|
|
Packit Service |
97d2fb |
fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else if (! ignore_build_id)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: build ID content"),
|
|
Packit Service |
97d2fb |
fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu] '%s' note '%s' content"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1,
|
|
Packit Service |
97d2fb |
name1);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
if (off2 < data2->d_size)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu] '%s' number of notes"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
default:
|
|
Packit Service |
97d2fb |
/* Compare the section content byte for byte. */
|
|
Packit Service |
97d2fb |
assert (shdr1->sh_type == SHT_NOBITS
|
|
Packit Service |
97d2fb |
|| (data1->d_buf != NULL || data1->d_size == 0));
|
|
Packit Service |
97d2fb |
assert (shdr2->sh_type == SHT_NOBITS
|
|
Packit Service |
97d2fb |
|| (data2->d_buf != NULL || data1->d_size == 0));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (unlikely (data1->d_size != data2->d_size
|
|
Packit Service |
97d2fb |
|| (shdr1->sh_type != SHT_NOBITS
|
|
Packit Service |
97d2fb |
&& data1->d_size != 0
|
|
Packit Service |
97d2fb |
&& memcmp (data1->d_buf, data2->d_buf,
|
|
Packit Service |
97d2fb |
data1->d_size) != 0)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (hash_inexact
|
|
Packit Service |
97d2fb |
&& shdr1->sh_type == SHT_HASH
|
|
Packit Service |
97d2fb |
&& data1->d_size == data2->d_size
|
|
Packit Service |
97d2fb |
&& hash_content_equivalent (shdr1->sh_entsize, data1, data2))
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (elf_ndxscn (scn1) == elf_ndxscn (scn2))
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu] '%s' content"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1), sname1);
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
%s %s differ: section [%zu,%zu] '%s' content"),
|
|
Packit Service |
97d2fb |
fname1, fname2, elf_ndxscn (scn1),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn2), sname1);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (unlikely (scn1 != scn2))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0,
|
|
Packit Service |
97d2fb |
gettext ("%s %s differ: unequal amount of important sections"),
|
|
Packit Service |
97d2fb |
fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* We we look at gaps, create artificial ones for the parts of the
|
|
Packit Service |
97d2fb |
program which we are not in sections. */
|
|
Packit Service |
97d2fb |
struct region ehdr_region;
|
|
Packit Service |
97d2fb |
struct region phdr_region;
|
|
Packit Service |
97d2fb |
if (gaps != gaps_ignore)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
ehdr_region.from = 0;
|
|
Packit Service |
97d2fb |
ehdr_region.to = ehdr1->e_ehsize;
|
|
Packit Service |
97d2fb |
ehdr_region.next = &phdr_region;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
phdr_region.from = ehdr1->e_phoff;
|
|
Packit Service |
97d2fb |
phdr_region.to = ehdr1->e_phoff + phnum1 * ehdr1->e_phentsize;
|
|
Packit Service |
97d2fb |
phdr_region.next = regions;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
regions = &ehdr_region;
|
|
Packit Service |
97d2fb |
nregions += 2;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* If we need to look at the gaps we need access to the file data. */
|
|
Packit Service |
97d2fb |
char *raw1 = NULL;
|
|
Packit Service |
97d2fb |
size_t size1 = 0;
|
|
Packit Service |
97d2fb |
char *raw2 = NULL;
|
|
Packit Service |
97d2fb |
size_t size2 = 0;
|
|
Packit Service |
97d2fb |
struct region *regionsarr = alloca (nregions * sizeof (struct region));
|
|
Packit Service |
97d2fb |
if (gaps != gaps_ignore)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
raw1 = elf_rawfile (elf1, &size1);
|
|
Packit Service |
97d2fb |
if (raw1 == NULL )
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot load data of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
raw2 = elf_rawfile (elf2, &size2);
|
|
Packit Service |
97d2fb |
if (raw2 == NULL )
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot load data of '%s': %s"),
|
|
Packit Service |
97d2fb |
fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
for (size_t cnt = 0; cnt < nregions; ++cnt)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
regionsarr[cnt] = *regions;
|
|
Packit Service |
97d2fb |
regions = regions->next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
qsort (regionsarr, nregions, sizeof (regionsarr[0]), regioncompare);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Compare the program header tables. */
|
|
Packit Service |
97d2fb |
for (unsigned int ndx = 0; ndx < phnum1; ++ndx)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Phdr phdr1_mem;
|
|
Packit Service |
97d2fb |
GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem);
|
|
Packit Service |
97d2fb |
if (phdr1 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get program header entry %d of '%s': %s"),
|
|
Packit Service |
97d2fb |
ndx, fname1, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
GElf_Phdr phdr2_mem;
|
|
Packit Service |
97d2fb |
GElf_Phdr *phdr2 = gelf_getphdr (elf2, ndx, &phdr2_mem);
|
|
Packit Service |
97d2fb |
if (phdr2 == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get program header entry %d of '%s': %s"),
|
|
Packit Service |
97d2fb |
ndx, fname2, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (unlikely (memcmp (phdr1, phdr2, sizeof (GElf_Phdr)) != 0))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (! quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s differ: program header %d"),
|
|
Packit Service |
97d2fb |
fname1, fname2, ndx);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (gaps != gaps_ignore && phdr1->p_type == PT_LOAD)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
size_t cnt = 0;
|
|
Packit Service |
97d2fb |
while (cnt < nregions && regionsarr[cnt].to < phdr1->p_offset)
|
|
Packit Service |
97d2fb |
++cnt;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
GElf_Off last = phdr1->p_offset;
|
|
Packit Service |
97d2fb |
GElf_Off end = phdr1->p_offset + phdr1->p_filesz;
|
|
Packit Service |
97d2fb |
while (cnt < nregions && regionsarr[cnt].from < end)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (last < regionsarr[cnt].from)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Compare the [LAST,FROM) region. */
|
|
Packit Service |
97d2fb |
assert (gaps == gaps_match);
|
|
Packit Service |
97d2fb |
if (unlikely (memcmp (raw1 + last, raw2 + last,
|
|
Packit Service |
97d2fb |
regionsarr[cnt].from - last) != 0))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
gapmismatch:
|
|
Packit Service |
97d2fb |
if (!quiet)
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("%s %s differ: gap"),
|
|
Packit Service |
97d2fb |
fname1, fname2);
|
|
Packit Service |
97d2fb |
DIFFERENCE;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
last = regionsarr[cnt].to;
|
|
Packit Service |
97d2fb |
++cnt;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (cnt == nregions && last < end)
|
|
Packit Service |
97d2fb |
goto gapmismatch;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
out:
|
|
Packit Service |
97d2fb |
elf_end (elf1);
|
|
Packit Service |
97d2fb |
elf_end (elf2);
|
|
Packit Service |
97d2fb |
ebl_closebackend (ebl1);
|
|
Packit Service |
97d2fb |
ebl_closebackend (ebl2);
|
|
Packit Service |
97d2fb |
close (fd1);
|
|
Packit Service |
97d2fb |
close (fd2);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
return result;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Handle program arguments. */
|
|
Packit Service |
97d2fb |
static error_t
|
|
Packit Service |
97d2fb |
parse_opt (int key, char *arg,
|
|
Packit Service |
97d2fb |
struct argp_state *state __attribute__ ((unused)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
switch (key)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
case 'q':
|
|
Packit Service |
97d2fb |
quiet = true;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case 'l':
|
|
Packit Service |
97d2fb |
verbose = true;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case OPT_GAPS:
|
|
Packit Service |
97d2fb |
if (strcasecmp (arg, "ignore") == 0)
|
|
Packit Service |
97d2fb |
gaps = gaps_ignore;
|
|
Packit Service |
97d2fb |
else if (likely (strcasecmp (arg, "match") == 0))
|
|
Packit Service |
97d2fb |
gaps = gaps_match;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
fprintf (stderr,
|
|
Packit Service |
97d2fb |
gettext ("Invalid value '%s' for --gaps parameter."),
|
|
Packit Service |
97d2fb |
arg);
|
|
Packit Service |
97d2fb |
argp_help (&argp, stderr, ARGP_HELP_SEE,
|
|
Packit Service |
97d2fb |
program_invocation_short_name);
|
|
Packit Service |
97d2fb |
exit (1);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case OPT_HASH_INEXACT:
|
|
Packit Service |
97d2fb |
hash_inexact = true;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case OPT_IGNORE_BUILD_ID:
|
|
Packit Service |
97d2fb |
ignore_build_id = true;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
default:
|
|
Packit Service |
97d2fb |
return ARGP_ERR_UNKNOWN;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static Elf *
|
|
Packit Service |
97d2fb |
open_file (const char *fname, int *fdp, Ebl **eblp)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
int fd = open (fname, O_RDONLY);
|
|
Packit Service |
97d2fb |
if (unlikely (fd == -1))
|
|
Packit Service |
97d2fb |
error (2, errno, gettext ("cannot open '%s'"), fname);
|
|
Packit Service |
97d2fb |
Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
|
|
Packit Service |
97d2fb |
if (elf == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot create ELF descriptor for '%s': %s"),
|
|
Packit Service |
97d2fb |
fname, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
Ebl *ebl = ebl_openbackend (elf);
|
|
Packit Service |
97d2fb |
if (ebl == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot create EBL descriptor for '%s'"), fname);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*fdp = fd;
|
|
Packit Service |
97d2fb |
*eblp = ebl;
|
|
Packit Service |
97d2fb |
return elf;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
search_for_copy_reloc (Ebl *ebl, size_t scnndx, int symndx)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Elf_Scn *scn = NULL;
|
|
Packit Service |
97d2fb |
while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Shdr shdr_mem;
|
|
Packit Service |
97d2fb |
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
|
Packit Service |
97d2fb |
if (shdr == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get section header of section %zu: %s"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn), elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if ((shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
|
|
Packit Service |
97d2fb |
|| shdr->sh_link != scnndx)
|
|
Packit Service |
97d2fb |
continue;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf_Data *data = elf_getdata (scn, NULL);
|
|
Packit Service |
97d2fb |
if (data == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get content of section %zu: %s"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn), elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (shdr->sh_type == SHT_REL && shdr->sh_entsize != 0)
|
|
Packit Service |
97d2fb |
for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
|
|
Packit Service |
97d2fb |
++ndx)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Rel rel_mem;
|
|
Packit Service |
97d2fb |
GElf_Rel *rel = gelf_getrel (data, ndx, &rel_mem);
|
|
Packit Service |
97d2fb |
if (rel == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get relocation: %s"),
|
|
Packit Service |
97d2fb |
elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if ((int) GELF_R_SYM (rel->r_info) == symndx
|
|
Packit Service |
97d2fb |
&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else if (shdr->sh_entsize != 0)
|
|
Packit Service |
97d2fb |
for (int ndx = 0; ndx < (int) (shdr->sh_size / shdr->sh_entsize);
|
|
Packit Service |
97d2fb |
++ndx)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Rela rela_mem;
|
|
Packit Service |
97d2fb |
GElf_Rela *rela = gelf_getrela (data, ndx, &rela_mem);
|
|
Packit Service |
97d2fb |
if (rela == NULL)
|
|
Packit Service |
97d2fb |
error (2, 0, gettext ("cannot get relocation: %s"),
|
|
Packit Service |
97d2fb |
elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if ((int) GELF_R_SYM (rela->r_info) == symndx
|
|
Packit Service |
97d2fb |
&& ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static int
|
|
Packit Service |
97d2fb |
regioncompare (const void *p1, const void *p2)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
const struct region *r1 = (const struct region *) p1;
|
|
Packit Service |
97d2fb |
const struct region *r2 = (const struct region *) p2;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (r1->from < r2->from)
|
|
Packit Service |
97d2fb |
return -1;
|
|
Packit Service |
97d2fb |
return 1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static int
|
|
Packit Service |
97d2fb |
compare_Elf32_Word (const void *p1, const void *p2)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
const Elf32_Word *w1 = p1;
|
|
Packit Service |
97d2fb |
const Elf32_Word *w2 = p2;
|
|
Packit Service |
97d2fb |
return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static int
|
|
Packit Service |
97d2fb |
compare_Elf64_Xword (const void *p1, const void *p2)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
const Elf64_Xword *w1 = p1;
|
|
Packit Service |
97d2fb |
const Elf64_Xword *w2 = p2;
|
|
Packit Service |
97d2fb |
return *w1 < *w2 ? -1 : *w1 > *w2 ? 1 : 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
hash_content_equivalent (size_t entsize, Elf_Data *data1, Elf_Data *data2)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
#define CHECK_HASH(Hash_Word) \
|
|
Packit Service |
97d2fb |
{ \
|
|
Packit Service |
97d2fb |
const Hash_Word *const hash1 = data1->d_buf; \
|
|
Packit Service |
97d2fb |
const Hash_Word *const hash2 = data2->d_buf; \
|
|
Packit Service |
97d2fb |
const size_t nbucket = hash1[0]; \
|
|
Packit Service |
97d2fb |
const size_t nchain = hash1[1]; \
|
|
Packit Service |
97d2fb |
if (data1->d_size != (2 + nbucket + nchain) * sizeof hash1[0] \
|
|
Packit Service |
97d2fb |
|| hash2[0] != nbucket || hash2[1] != nchain) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
const Hash_Word *const bucket1 = &hash1[2]; \
|
|
Packit Service |
97d2fb |
const Hash_Word *const chain1 = &bucket1[nbucket]; \
|
|
Packit Service |
97d2fb |
const Hash_Word *const bucket2 = &hash2[2]; \
|
|
Packit Service |
97d2fb |
const Hash_Word *const chain2 = &bucket2[nbucket]; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
bool chain_ok[nchain]; \
|
|
Packit Service |
97d2fb |
Hash_Word temp1[nchain - 1]; \
|
|
Packit Service |
97d2fb |
Hash_Word temp2[nchain - 1]; \
|
|
Packit Service |
97d2fb |
memset (chain_ok, 0, sizeof chain_ok); \
|
|
Packit Service |
97d2fb |
for (size_t i = 0; i < nbucket; ++i) \
|
|
Packit Service |
97d2fb |
{ \
|
|
Packit Service |
97d2fb |
if (bucket1[i] >= nchain || bucket2[i] >= nchain) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
size_t b1 = 0; \
|
|
Packit Service |
97d2fb |
for (size_t p = bucket1[i]; p != STN_UNDEF; p = chain1[p]) \
|
|
Packit Service |
97d2fb |
if (p >= nchain || b1 >= nchain - 1) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
else \
|
|
Packit Service |
97d2fb |
temp1[b1++] = p; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
size_t b2 = 0; \
|
|
Packit Service |
97d2fb |
for (size_t p = bucket2[i]; p != STN_UNDEF; p = chain2[p]) \
|
|
Packit Service |
97d2fb |
if (p >= nchain || b2 >= nchain - 1) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
else \
|
|
Packit Service |
97d2fb |
temp2[b2++] = p; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
if (b1 != b2) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
qsort (temp1, b1, sizeof temp1[0], compare_##Hash_Word); \
|
|
Packit Service |
97d2fb |
qsort (temp2, b2, sizeof temp2[0], compare_##Hash_Word); \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
for (b1 = 0; b1 < b2; ++b1) \
|
|
Packit Service |
97d2fb |
if (temp1[b1] != temp2[b1]) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
else \
|
|
Packit Service |
97d2fb |
chain_ok[temp1[b1]] = true; \
|
|
Packit Service |
97d2fb |
} \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
for (size_t i = 0; i < nchain; ++i) \
|
|
Packit Service |
97d2fb |
if (!chain_ok[i] && chain1[i] != chain2[i]) \
|
|
Packit Service |
97d2fb |
return false; \
|
|
Packit Service |
97d2fb |
\
|
|
Packit Service |
97d2fb |
return true; \
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
switch (entsize)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
case 4:
|
|
Packit Service |
97d2fb |
CHECK_HASH (Elf32_Word);
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
case 8:
|
|
Packit Service |
97d2fb |
CHECK_HASH (Elf64_Xword);
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include "debugpred.h"
|