|
Packit Service |
97d2fb |
/* Locate source files or functions which caused text relocations.
|
|
Packit Service |
97d2fb |
Copyright (C) 2005-2010, 2012, 2014, 2018 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 <gelf.h>
|
|
Packit Service |
97d2fb |
#include <libdw.h>
|
|
Packit Service |
97d2fb |
#include <libintl.h>
|
|
Packit Service |
97d2fb |
#include <locale.h>
|
|
Packit Service |
97d2fb |
#include <search.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 "system.h"
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct segments
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Addr from;
|
|
Packit Service |
97d2fb |
GElf_Addr to;
|
|
Packit Service |
97d2fb |
};
|
|
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_DEBUGINFO 0x100
|
|
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_("Input Selection:"), 0 },
|
|
Packit Service |
97d2fb |
{ "root", 'r', "PATH", 0, N_("Prepend PATH to all file names"), 0 },
|
|
Packit Service |
97d2fb |
{ "debuginfo", OPT_DEBUGINFO, "PATH", 0,
|
|
Packit Service |
97d2fb |
N_("Use PATH as root of debuginfo hierarchy"), 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 |
Locate source of text relocations in FILEs (a.out by default).");
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Strings for arguments in help texts. */
|
|
Packit Service |
97d2fb |
static const char args_doc[] = N_("[FILE...]");
|
|
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 |
/* Print symbols in file named FNAME. */
|
|
Packit Service |
97d2fb |
static int process_file (const char *fname, bool more_than_one);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Check for text relocations in the given file. The segment
|
|
Packit Service |
97d2fb |
information is known. */
|
|
Packit Service |
97d2fb |
static void check_rel (size_t nsegments, struct segments segments[nsegments],
|
|
Packit Service |
97d2fb |
GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw,
|
|
Packit Service |
97d2fb |
const char *fname, bool more_than_one,
|
|
Packit Service |
97d2fb |
void **knownsrcs);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* User-provided root directory. */
|
|
Packit Service |
97d2fb |
static const char *rootdir = "/";
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Root of debuginfo directory hierarchy. */
|
|
Packit Service |
97d2fb |
static const char *debuginfo_root;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
int
|
|
Packit Service |
97d2fb |
main (int argc, char *argv[])
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
int remaining;
|
|
Packit Service |
97d2fb |
int result = 0;
|
|
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 |
(void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Tell the library which version we are expecting. */
|
|
Packit Service |
97d2fb |
elf_version (EV_CURRENT);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* If the user has not specified the root directory for the
|
|
Packit Service |
97d2fb |
debuginfo hierarchy, we have to determine it ourselves. */
|
|
Packit Service |
97d2fb |
if (debuginfo_root == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
// XXX The runtime should provide this information.
|
|
Packit Service |
97d2fb |
#if defined __ia64__ || defined __alpha__
|
|
Packit Service |
97d2fb |
debuginfo_root = "/usr/lib/debug";
|
|
Packit Service |
97d2fb |
#else
|
|
Packit Service |
97d2fb |
debuginfo_root = (sizeof (long int) == 4
|
|
Packit Service |
97d2fb |
? "/usr/lib/debug" : "/usr/lib64/debug");
|
|
Packit Service |
97d2fb |
#endif
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (remaining == argc)
|
|
Packit Service |
97d2fb |
result = process_file ("a.out", false);
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Process all the remaining files. */
|
|
Packit Service |
97d2fb |
const bool more_than_one = remaining + 1 < argc;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
do
|
|
Packit Service |
97d2fb |
result |= process_file (argv[remaining], more_than_one);
|
|
Packit Service |
97d2fb |
while (++remaining < argc);
|
|
Packit Service |
97d2fb |
}
|
|
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 'r':
|
|
Packit Service |
97d2fb |
rootdir = arg;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case OPT_DEBUGINFO:
|
|
Packit Service |
97d2fb |
debuginfo_root = arg;
|
|
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 void
|
|
Packit Service |
97d2fb |
noop (void *arg __attribute__ ((unused)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static int
|
|
Packit Service |
97d2fb |
process_file (const char *fname, bool more_than_one)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
int result = 0;
|
|
Packit Service |
97d2fb |
void *knownsrcs = NULL;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t fname_len = strlen (fname);
|
|
Packit Service |
97d2fb |
size_t rootdir_len = strlen (rootdir);
|
|
Packit Service |
97d2fb |
const char *real_fname = fname;
|
|
Packit Service |
97d2fb |
if (fname[0] == '/' && (rootdir[0] != '/' || rootdir[1] != '\0'))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Prepend the user-provided root directory. */
|
|
Packit Service |
97d2fb |
char *new_fname = alloca (rootdir_len + fname_len + 2);
|
|
Packit Service |
97d2fb |
*((char *) mempcpy (stpcpy (mempcpy (new_fname, rootdir, rootdir_len),
|
|
Packit Service |
97d2fb |
"/"),
|
|
Packit Service |
97d2fb |
fname, fname_len)) = '\0';
|
|
Packit Service |
97d2fb |
real_fname = new_fname;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
int fd = open (real_fname, O_RDONLY);
|
|
Packit Service |
97d2fb |
if (fd == -1)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, errno, gettext ("cannot open '%s'"), fname);
|
|
Packit Service |
97d2fb |
return 1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
|
|
Packit Service |
97d2fb |
if (elf == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("cannot create ELF descriptor for '%s': %s"),
|
|
Packit Service |
97d2fb |
fname, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
goto err_close;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Make sure the file is a DSO. */
|
|
Packit Service |
97d2fb |
GElf_Ehdr ehdr_mem;
|
|
Packit Service |
97d2fb |
GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
|
|
Packit Service |
97d2fb |
if (ehdr == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("cannot get ELF header '%s': %s"),
|
|
Packit Service |
97d2fb |
fname, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
err_elf_close:
|
|
Packit Service |
97d2fb |
elf_end (elf);
|
|
Packit Service |
97d2fb |
err_close:
|
|
Packit Service |
97d2fb |
close (fd);
|
|
Packit Service |
97d2fb |
return 1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (ehdr->e_type != ET_DYN)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("'%s' is not a DSO or PIE"), fname);
|
|
Packit Service |
97d2fb |
goto err_elf_close;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Determine whether the DSO has text relocations at all and locate
|
|
Packit Service |
97d2fb |
the symbol table. */
|
|
Packit Service |
97d2fb |
Elf_Scn *symscn = NULL;
|
|
Packit Service |
97d2fb |
Elf_Scn *scn = NULL;
|
|
Packit Service |
97d2fb |
bool seen_dynamic = false;
|
|
Packit Service |
97d2fb |
bool have_textrel = false;
|
|
Packit Service |
97d2fb |
while ((scn = elf_nextscn (elf, scn)) != NULL
|
|
Packit Service |
97d2fb |
&& (!seen_dynamic || symscn == NULL))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Handle the section if it is a symbol table. */
|
|
Packit Service |
97d2fb |
GElf_Shdr shdr_mem;
|
|
Packit Service |
97d2fb |
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (shdr == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0,
|
|
Packit Service |
97d2fb |
gettext ("getting get section header of section %zu: %s"),
|
|
Packit Service |
97d2fb |
elf_ndxscn (scn), elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
goto err_elf_close;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
switch (shdr->sh_type)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
case SHT_DYNAMIC:
|
|
Packit Service |
97d2fb |
if (!seen_dynamic)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
seen_dynamic = true;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf_Data *data = elf_getdata (scn, NULL);
|
|
Packit Service |
97d2fb |
size_t entries = (shdr->sh_entsize == 0
|
|
Packit Service |
97d2fb |
? 0 : shdr->sh_size / shdr->sh_entsize);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
for (size_t cnt = 0; cnt < entries; ++cnt)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Dyn dynmem;
|
|
Packit Service |
97d2fb |
GElf_Dyn *dyn;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
dyn = gelf_getdyn (data, cnt, &dynmem);
|
|
Packit Service |
97d2fb |
if (dyn == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("cannot read dynamic section: %s"),
|
|
Packit Service |
97d2fb |
elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
goto err_elf_close;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (dyn->d_tag == DT_TEXTREL
|
|
Packit Service |
97d2fb |
|| (dyn->d_tag == DT_FLAGS
|
|
Packit Service |
97d2fb |
&& (dyn->d_un.d_val & DF_TEXTREL) != 0))
|
|
Packit Service |
97d2fb |
have_textrel = true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
case SHT_SYMTAB:
|
|
Packit Service |
97d2fb |
symscn = scn;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (!have_textrel)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("no text relocations reported in '%s'"), fname);
|
|
Packit Service |
97d2fb |
goto err_elf_close;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
int fd2 = -1;
|
|
Packit Service |
97d2fb |
Elf *elf2 = NULL;
|
|
Packit Service |
97d2fb |
/* Get the address ranges for the loaded segments. */
|
|
Packit Service |
97d2fb |
size_t nsegments_max = 10;
|
|
Packit Service |
97d2fb |
size_t nsegments = 0;
|
|
Packit Service |
97d2fb |
struct segments *segments
|
|
Packit Service |
97d2fb |
= (struct segments *) malloc (nsegments_max * sizeof (segments[0]));
|
|
Packit Service |
97d2fb |
if (segments == NULL)
|
|
Packit Service |
97d2fb |
error (1, errno, gettext ("while reading ELF file"));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
size_t phnum;
|
|
Packit Service |
97d2fb |
if (elf_getphdrnum (elf, &phnum) != 0)
|
|
Packit Service |
97d2fb |
error (1, 0, gettext ("cannot get program header count: %s"),
|
|
Packit Service |
97d2fb |
elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
for (size_t i = 0; i < phnum; ++i)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Phdr phdr_mem;
|
|
Packit Service |
97d2fb |
GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
|
|
Packit Service |
97d2fb |
if (phdr == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0,
|
|
Packit Service |
97d2fb |
gettext ("cannot get program header index at offset %zd: %s"),
|
|
Packit Service |
97d2fb |
i, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
result = 1;
|
|
Packit Service |
97d2fb |
goto next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (nsegments == nsegments_max)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
nsegments_max *= 2;
|
|
Packit Service |
97d2fb |
segments
|
|
Packit Service |
97d2fb |
= (struct segments *) realloc (segments,
|
|
Packit Service |
97d2fb |
nsegments_max
|
|
Packit Service |
97d2fb |
* sizeof (segments[0]));
|
|
Packit Service |
97d2fb |
if (segments == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
cannot get program header index at offset %zd: %s"),
|
|
Packit Service |
97d2fb |
i, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
result = 1;
|
|
Packit Service |
97d2fb |
goto next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
segments[nsegments].from = phdr->p_vaddr;
|
|
Packit Service |
97d2fb |
segments[nsegments].to = phdr->p_vaddr + phdr->p_memsz;
|
|
Packit Service |
97d2fb |
++nsegments;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (nsegments > 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL);
|
|
Packit Service |
97d2fb |
/* Look for debuginfo files if the information is not the in
|
|
Packit Service |
97d2fb |
opened file itself. This makes only sense if the input file
|
|
Packit Service |
97d2fb |
is specified with an absolute path. */
|
|
Packit Service |
97d2fb |
if (dw == NULL && fname[0] == '/')
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
size_t debuginfo_rootlen = strlen (debuginfo_root);
|
|
Packit Service |
97d2fb |
char *difname = (char *) alloca (rootdir_len + debuginfo_rootlen
|
|
Packit Service |
97d2fb |
+ fname_len + 8);
|
|
Packit Service |
97d2fb |
strcpy (mempcpy (stpcpy (mempcpy (mempcpy (difname, rootdir,
|
|
Packit Service |
97d2fb |
rootdir_len),
|
|
Packit Service |
97d2fb |
debuginfo_root,
|
|
Packit Service |
97d2fb |
debuginfo_rootlen),
|
|
Packit Service |
97d2fb |
"/"),
|
|
Packit Service |
97d2fb |
fname, fname_len),
|
|
Packit Service |
97d2fb |
".debug");
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
fd2 = open (difname, O_RDONLY);
|
|
Packit Service |
97d2fb |
if (fd2 != -1
|
|
Packit Service |
97d2fb |
&& (elf2 = elf_begin (fd2, ELF_C_READ_MMAP, NULL)) != NULL)
|
|
Packit Service |
97d2fb |
dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Look at all relocations and determine which modify
|
|
Packit Service |
97d2fb |
write-protected segments. */
|
|
Packit Service |
97d2fb |
scn = NULL;
|
|
Packit Service |
97d2fb |
while ((scn = elf_nextscn (elf, scn)) != NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Handle the section if it is a symbol table. */
|
|
Packit Service |
97d2fb |
GElf_Shdr shdr_mem;
|
|
Packit Service |
97d2fb |
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (shdr == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 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 |
result = 1;
|
|
Packit Service |
97d2fb |
goto next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
|
|
Packit Service |
97d2fb |
&& symscn == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
symscn = elf_getscn (elf, shdr->sh_link);
|
|
Packit Service |
97d2fb |
if (symscn == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
cannot get symbol table section %zu in '%s': %s"),
|
|
Packit Service |
97d2fb |
(size_t) shdr->sh_link, fname, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
result = 1;
|
|
Packit Service |
97d2fb |
goto next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (shdr->sh_type == SHT_REL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Elf_Data *data = elf_getdata (scn, NULL);
|
|
Packit Service |
97d2fb |
size_t entries = (shdr->sh_entsize == 0
|
|
Packit Service |
97d2fb |
? 0 : shdr->sh_size / shdr->sh_entsize);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
for (int cnt = 0;
|
|
Packit Service |
97d2fb |
(size_t) cnt < entries; ++cnt)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Rel rel_mem;
|
|
Packit Service |
97d2fb |
GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem);
|
|
Packit Service |
97d2fb |
if (rel == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
cannot get relocation at index %d in section %zu in '%s': %s"),
|
|
Packit Service |
97d2fb |
cnt, elf_ndxscn (scn), fname, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
result = 1;
|
|
Packit Service |
97d2fb |
goto next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
check_rel (nsegments, segments, rel->r_offset, elf,
|
|
Packit Service |
97d2fb |
symscn, dw, fname, more_than_one, &knownsrcs);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else if (shdr->sh_type == SHT_RELA)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Elf_Data *data = elf_getdata (scn, NULL);
|
|
Packit Service |
97d2fb |
size_t entries = (shdr->sh_entsize == 0
|
|
Packit Service |
97d2fb |
? 0 : shdr->sh_size / shdr->sh_entsize);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
for (int cnt = 0; (size_t) cnt < entries; ++cnt)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Rela rela_mem;
|
|
Packit Service |
97d2fb |
GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem);
|
|
Packit Service |
97d2fb |
if (rela == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
error (0, 0, gettext ("\
|
|
Packit Service |
97d2fb |
cannot get relocation at index %d in section %zu in '%s': %s"),
|
|
Packit Service |
97d2fb |
cnt, elf_ndxscn (scn), fname, elf_errmsg (-1));
|
|
Packit Service |
97d2fb |
result = 1;
|
|
Packit Service |
97d2fb |
goto next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
check_rel (nsegments, segments, rela->r_offset, elf,
|
|
Packit Service |
97d2fb |
symscn, dw, fname, more_than_one, &knownsrcs);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
dwarf_end (dw);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
next:
|
|
Packit Service |
97d2fb |
elf_end (elf);
|
|
Packit Service |
97d2fb |
elf_end (elf2);
|
|
Packit Service |
97d2fb |
close (fd);
|
|
Packit Service |
97d2fb |
if (fd2 != -1)
|
|
Packit Service |
97d2fb |
close (fd2);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
free (segments);
|
|
Packit Service |
97d2fb |
tdestroy (knownsrcs, noop);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
return result;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static int
|
|
Packit Service |
97d2fb |
ptrcompare (const void *p1, const void *p2)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if ((uintptr_t) p1 < (uintptr_t) p2)
|
|
Packit Service |
97d2fb |
return -1;
|
|
Packit Service |
97d2fb |
if ((uintptr_t) p1 > (uintptr_t) p2)
|
|
Packit Service |
97d2fb |
return 1;
|
|
Packit Service |
97d2fb |
return 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static void
|
|
Packit Service |
97d2fb |
check_rel (size_t nsegments, struct segments segments[nsegments],
|
|
Packit Service |
97d2fb |
GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw,
|
|
Packit Service |
97d2fb |
const char *fname, bool more_than_one, void **knownsrcs)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
for (size_t cnt = 0; cnt < nsegments; ++cnt)
|
|
Packit Service |
97d2fb |
if (segments[cnt].from <= addr && segments[cnt].to > addr)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Dwarf_Die die_mem;
|
|
Packit Service |
97d2fb |
Dwarf_Die *die;
|
|
Packit Service |
97d2fb |
Dwarf_Line *line;
|
|
Packit Service |
97d2fb |
const char *src;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (more_than_one)
|
|
Packit Service |
97d2fb |
printf ("%s: ", fname);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if ((die = dwarf_addrdie (dw, addr, &die_mem)) != NULL
|
|
Packit Service |
97d2fb |
&& (line = dwarf_getsrc_die (die, addr)) != NULL
|
|
Packit Service |
97d2fb |
&& (src = dwarf_linesrc (line, NULL, NULL)) != NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* There can be more than one relocation against one file.
|
|
Packit Service |
97d2fb |
Try to avoid multiple messages. And yes, the code uses
|
|
Packit Service |
97d2fb |
pointer comparison. */
|
|
Packit Service |
97d2fb |
if (tfind (src, knownsrcs, ptrcompare) == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
printf (gettext ("%s not compiled with -fpic/-fPIC\n"), src);
|
|
Packit Service |
97d2fb |
tsearch (src, knownsrcs, ptrcompare);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* At least look at the symbol table to see which function
|
|
Packit Service |
97d2fb |
the modified address is in. */
|
|
Packit Service |
97d2fb |
Elf_Data *symdata = elf_getdata (symscn, NULL);
|
|
Packit Service |
97d2fb |
GElf_Shdr shdr_mem;
|
|
Packit Service |
97d2fb |
GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
|
|
Packit Service |
97d2fb |
if (shdr != NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
GElf_Addr lowaddr = 0;
|
|
Packit Service |
97d2fb |
int lowidx = -1;
|
|
Packit Service |
97d2fb |
GElf_Addr highaddr = ~0ul;
|
|
Packit Service |
97d2fb |
int highidx = -1;
|
|
Packit Service |
97d2fb |
GElf_Sym sym_mem;
|
|
Packit Service |
97d2fb |
GElf_Sym *sym;
|
|
Packit Service |
97d2fb |
size_t entries = (shdr->sh_entsize == 0
|
|
Packit Service |
97d2fb |
? 0 : shdr->sh_size / shdr->sh_entsize);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
for (int i = 0; (size_t) i < entries; ++i)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
sym = gelf_getsym (symdata, i, &sym_mem);
|
|
Packit Service |
97d2fb |
if (sym == NULL)
|
|
Packit Service |
97d2fb |
continue;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (sym->st_value < addr && sym->st_value > lowaddr)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
lowaddr = sym->st_value;
|
|
Packit Service |
97d2fb |
lowidx = i;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
if (sym->st_value > addr && sym->st_value < highaddr)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
highaddr = sym->st_value;
|
|
Packit Service |
97d2fb |
highidx = i;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (lowidx != -1)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
sym = gelf_getsym (symdata, lowidx, &sym_mem);
|
|
Packit Service |
97d2fb |
assert (sym != NULL);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
const char *lowstr = elf_strptr (elf, shdr->sh_link,
|
|
Packit Service |
97d2fb |
sym->st_name);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (sym->st_value + sym->st_size > addr)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* It is this function. */
|
|
Packit Service |
97d2fb |
if (tfind (lowstr, knownsrcs, ptrcompare) == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
printf (gettext ("\
|
|
Packit Service |
97d2fb |
the file containing the function '%s' is not compiled with -fpic/-fPIC\n"),
|
|
Packit Service |
97d2fb |
lowstr);
|
|
Packit Service |
97d2fb |
tsearch (lowstr, knownsrcs, ptrcompare);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else if (highidx == -1)
|
|
Packit Service |
97d2fb |
printf (gettext ("\
|
|
Packit Service |
97d2fb |
the file containing the function '%s' might not be compiled with -fpic/-fPIC\n"),
|
|
Packit Service |
97d2fb |
lowstr);
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
sym = gelf_getsym (symdata, highidx, &sym_mem);
|
|
Packit Service |
97d2fb |
assert (sym != NULL);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
printf (gettext ("\
|
|
Packit Service |
97d2fb |
either the file containing the function '%s' or the file containing the function '%s' is not compiled with -fpic/-fPIC\n"),
|
|
Packit Service |
97d2fb |
lowstr, elf_strptr (elf, shdr->sh_link,
|
|
Packit Service |
97d2fb |
sym->st_name));
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else if (highidx != -1)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
sym = gelf_getsym (symdata, highidx, &sym_mem);
|
|
Packit Service |
97d2fb |
assert (sym != NULL);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
printf (gettext ("\
|
|
Packit Service |
97d2fb |
the file containing the function '%s' might not be compiled with -fpic/-fPIC\n"),
|
|
Packit Service |
97d2fb |
elf_strptr (elf, shdr->sh_link, sym->st_name));
|
|
Packit Service |
97d2fb |
return;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
printf (gettext ("\
|
|
Packit Service |
97d2fb |
a relocation modifies memory at offset %llu in a write-protected segment\n"),
|
|
Packit Service |
97d2fb |
(unsigned long long int) addr);
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include "debugpred.h"
|