Blame src/findtextrel.c

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"