Blame libdwfl/relocate.c

Packit Service 97d2fb
/* Relocate debug information.
Packit Service 97d2fb
   Copyright (C) 2005-2011, 2014, 2016, 2018 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
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 either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
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 GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   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 "libelfP.h"
Packit Service 97d2fb
#include "libdwflP.h"
Packit Service 97d2fb
Packit Service 97d2fb
typedef uint8_t GElf_Byte;
Packit Service 97d2fb
Packit Service 97d2fb
/* Adjust *VALUE to add the load address of the SHNDX section.
Packit Service 97d2fb
   We update the section header in place to cache the result.  */
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl_Error
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
Packit Service 97d2fb
			  Elf32_Word shndx, GElf_Addr *value)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* No adjustment needed for section zero, it is never loaded.
Packit Service 97d2fb
     Handle it first, just in case the ELF file has strange section
Packit Service 97d2fb
     zero flags set.  */
Packit Service 97d2fb
  if (shndx == 0)
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *refscn = elf_getscn (elf, shndx);
Packit Service 97d2fb
  GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
Packit Service 97d2fb
  if (refshdr == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This is a loaded section.  Find its actual
Packit Service 97d2fb
	 address and update the section header.  */
Packit Service 97d2fb
Packit Service 97d2fb
      if (*shstrndx == SHN_UNDEF
Packit Service 97d2fb
	  && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
Packit Service 97d2fb
      if (unlikely (name == NULL))
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
      if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
Packit Service 97d2fb
						    name, shndx, refshdr,
Packit Service 97d2fb
						    &refshdr->sh_addr))
Packit Service 97d2fb
	return CBFAIL;
Packit Service 97d2fb
Packit Service 97d2fb
      if (refshdr->sh_addr == (Dwarf_Addr) -1l)
Packit Service 97d2fb
	/* The callback indicated this section wasn't really loaded but we
Packit Service 97d2fb
	   don't really care.  */
Packit Service 97d2fb
	refshdr->sh_addr = 0;	/* Make no adjustment below.  */
Packit Service 97d2fb
Packit Service 97d2fb
      /* Update the in-core file's section header to show the final
Packit Service 97d2fb
	 load address (or unloadedness).  This serves as a cache,
Packit Service 97d2fb
	 so we won't get here again for the same section.  */
Packit Service 97d2fb
      if (likely (refshdr->sh_addr != 0)
Packit Service 97d2fb
	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (refshdr->sh_flags & SHF_ALLOC)
Packit Service 97d2fb
    /* Apply the adjustment.  */
Packit Service 97d2fb
    *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
Packit Service 97d2fb
Packit Service 97d2fb
  return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Cache used by relocate_getsym.  */
Packit Service 97d2fb
struct reloc_symtab_cache
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf *symelf;
Packit Service 97d2fb
  Elf_Data *symdata;
Packit Service 97d2fb
  Elf_Data *symxndxdata;
Packit Service 97d2fb
  Elf_Data *symstrdata;
Packit Service 97d2fb
  size_t symshstrndx;
Packit Service 97d2fb
  size_t strtabndx;
Packit Service 97d2fb
};
Packit Service 97d2fb
#define RELOC_SYMTAB_CACHE(cache)	\
Packit Service 97d2fb
  struct reloc_symtab_cache cache =	\
Packit Service 97d2fb
    { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
Packit Service 97d2fb
Packit Service 97d2fb
/* This is just doing dwfl_module_getsym, except that we must always use
Packit Service 97d2fb
   the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
relocate_getsym (Dwfl_Module *mod,
Packit Service 97d2fb
		 Elf *relocated, struct reloc_symtab_cache *cache,
Packit Service 97d2fb
		 int symndx, GElf_Sym *sym, GElf_Word *shndx)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (cache->symdata == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (mod->symfile == NULL || mod->symfile->elf != relocated)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We have to look up the symbol table in the file we are
Packit Service 97d2fb
	     relocating, if it has its own.  These reloc sections refer to
Packit Service 97d2fb
	     the symbol table in this file, and a symbol table in the main
Packit Service 97d2fb
	     file might not match.  However, some tools did produce ET_REL
Packit Service 97d2fb
	     .debug files with relocs but no symtab of their own.  */
Packit Service 97d2fb
	  Elf_Scn *scn = NULL;
Packit Service 97d2fb
	  while ((scn = elf_nextscn (relocated, scn)) != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	      if (shdr != NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* We need uncompressed data.  */
Packit Service 97d2fb
		  if ((shdr->sh_type == SHT_SYMTAB
Packit Service 97d2fb
		       || shdr->sh_type == SHT_SYMTAB_SHNDX)
Packit Service 97d2fb
		      && (shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
		    if (elf_compress (scn, 0, 0) < 0)
Packit Service 97d2fb
		      return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
		  switch (shdr->sh_type)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		    default:
Packit Service 97d2fb
		      continue;
Packit Service 97d2fb
		    case SHT_SYMTAB:
Packit Service 97d2fb
		      cache->symelf = relocated;
Packit Service 97d2fb
		      cache->symdata = elf_getdata (scn, NULL);
Packit Service 97d2fb
		      cache->strtabndx = shdr->sh_link;
Packit Service 97d2fb
		      if (unlikely (cache->symdata == NULL))
Packit Service 97d2fb
			return DWFL_E_LIBELF;
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
		    case SHT_SYMTAB_SHNDX:
Packit Service 97d2fb
		      cache->symxndxdata = elf_getdata (scn, NULL);
Packit Service 97d2fb
		      if (unlikely (cache->symxndxdata == NULL))
Packit Service 97d2fb
			return DWFL_E_LIBELF;
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
Packit Service 97d2fb
		break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (cache->symdata == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We might not have looked for a symbol table file yet,
Packit Service 97d2fb
	     when coming from __libdwfl_relocate_section.  */
Packit Service 97d2fb
	  if (unlikely (mod->symfile == NULL)
Packit Service 97d2fb
	      && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
Packit Service 97d2fb
	    return dwfl_errno ();
Packit Service 97d2fb
Packit Service 97d2fb
	  /* The symbol table we have already cached is the one from
Packit Service 97d2fb
	     the file being relocated, so it's what we need.  Or else
Packit Service 97d2fb
	     this is an ET_REL .debug file with no .symtab of its own;
Packit Service 97d2fb
	     the symbols refer to the section indices in the main file.  */
Packit Service 97d2fb
	  cache->symelf = mod->symfile->elf;
Packit Service 97d2fb
	  cache->symdata = mod->symdata;
Packit Service 97d2fb
	  cache->symxndxdata = mod->symxndxdata;
Packit Service 97d2fb
	  cache->symstrdata = mod->symstrdata;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
Packit Service 97d2fb
				  symndx, sym, shndx) == NULL))
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  if (sym->st_shndx != SHN_XINDEX)
Packit Service 97d2fb
    *shndx = sym->st_shndx;
Packit Service 97d2fb
Packit Service 97d2fb
  switch (sym->st_shndx)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case SHN_ABS:
Packit Service 97d2fb
    case SHN_UNDEF:
Packit Service 97d2fb
      return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
    case SHN_COMMON:
Packit Service 97d2fb
      sym->st_value = 0;	/* Value is size, not helpful. */
Packit Service 97d2fb
      return DWFL_E_NOERROR;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
Packit Service 97d2fb
				   *shndx, &sym->st_value);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle an undefined symbol.  We really only support ET_REL for Linux
Packit Service 97d2fb
   kernel modules, and offline archives.  The behavior of the Linux module
Packit Service 97d2fb
   loader is very simple and easy to mimic.  It only matches magically
Packit Service 97d2fb
   exported symbols, and we match any defined symbols.  But we get the same
Packit Service 97d2fb
   answer except when the module's symbols are undefined and would prevent
Packit Service 97d2fb
   it from being loaded.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
Packit Service 97d2fb
		GElf_Sym *sym, GElf_Word shndx)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* First we need its name.  */
Packit Service 97d2fb
  if (sym->st_name != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (symtab->symstrdata == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Cache the strtab for this symtab.  */
Packit Service 97d2fb
	  assert (referer->symfile == NULL
Packit Service 97d2fb
		  || referer->symfile->elf != symtab->symelf);
Packit Service 97d2fb
Packit Service 97d2fb
	  Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
Packit Service 97d2fb
	  if (scn == NULL)
Packit Service 97d2fb
	    return DWFL_E_LIBELF;
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
	    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (symtab->symshstrndx == SHN_UNDEF
Packit Service 97d2fb
	      && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
Packit Service 97d2fb
	    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
	  const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
Packit Service 97d2fb
					  shdr->sh_name);
Packit Service 97d2fb
	  if (sname == NULL)
Packit Service 97d2fb
	    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* If the section is already decompressed, that isn't an error.  */
Packit Service 97d2fb
	  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
Packit Service 97d2fb
	    elf_compress_gnu (scn, 0, 0);
Packit Service 97d2fb
Packit Service 97d2fb
	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
	    if (elf_compress (scn, 0, 0) < 0)
Packit Service 97d2fb
	      return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
	  symtab->symstrdata = elf_getdata (scn, NULL);
Packit Service 97d2fb
	  if (unlikely (symtab->symstrdata == NULL
Packit Service 97d2fb
			|| symtab->symstrdata->d_buf == NULL))
Packit Service 97d2fb
	    return DWFL_E_LIBELF;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
Packit Service 97d2fb
	return DWFL_E_BADSTROFF;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *name = symtab->symstrdata->d_buf;
Packit Service 97d2fb
      name += sym->st_name;
Packit Service 97d2fb
Packit Service 97d2fb
      for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
Packit Service 97d2fb
	if (m != referer)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    /* Get this module's symtab.
Packit Service 97d2fb
	       If we got a fresh error reading the table, report it.
Packit Service 97d2fb
	       If we just have no symbols in this module, no harm done.  */
Packit Service 97d2fb
	    if (m->symdata == NULL
Packit Service 97d2fb
		&& m->symerr == DWFL_E_NOERROR
Packit Service 97d2fb
		&& INTUSE(dwfl_module_getsymtab) (m) < 0
Packit Service 97d2fb
		&& m->symerr != DWFL_E_NO_SYMTAB)
Packit Service 97d2fb
	      return m->symerr;
Packit Service 97d2fb
Packit Service 97d2fb
	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
Packit Service 97d2fb
					ndx, sym, &shndx);
Packit Service 97d2fb
		if (unlikely (sym == NULL))
Packit Service 97d2fb
		  return DWFL_E_LIBELF;
Packit Service 97d2fb
		if (sym->st_shndx != SHN_XINDEX)
Packit Service 97d2fb
		  shndx = sym->st_shndx;
Packit Service 97d2fb
Packit Service 97d2fb
		/* We are looking for a defined global symbol with a name.  */
Packit Service 97d2fb
		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
Packit Service 97d2fb
		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
Packit Service 97d2fb
		    || sym->st_name == 0)
Packit Service 97d2fb
		  continue;
Packit Service 97d2fb
Packit Service 97d2fb
		/* Get this candidate symbol's name.  */
Packit Service 97d2fb
		if (unlikely (sym->st_name >= m->symstrdata->d_size))
Packit Service 97d2fb
		  return DWFL_E_BADSTROFF;
Packit Service 97d2fb
		const char *n = m->symstrdata->d_buf;
Packit Service 97d2fb
		n += sym->st_name;
Packit Service 97d2fb
Packit Service 97d2fb
		/* Does the name match?  */
Packit Service 97d2fb
		if (strcmp (name, n))
Packit Service 97d2fb
		  continue;
Packit Service 97d2fb
Packit Service 97d2fb
		/* We found it!  */
Packit Service 97d2fb
		if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
Packit Service 97d2fb
		  return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
		if (m->e_type != ET_REL)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    sym->st_value = dwfl_adjusted_st_value (m, m->symfile->elf,
Packit Service 97d2fb
							    sym->st_value);
Packit Service 97d2fb
		    return DWFL_E_NOERROR;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
Packit Service 97d2fb
		/* In an ET_REL file, the symbol table values are relative
Packit Service 97d2fb
		   to the section, not to the module's load base.  */
Packit Service 97d2fb
		size_t symshstrndx = SHN_UNDEF;
Packit Service 97d2fb
		return __libdwfl_relocate_value (m, m->symfile->elf,
Packit Service 97d2fb
						 &symshstrndx,
Packit Service 97d2fb
						 shndx, &sym->st_value);
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	  }
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return DWFL_E_RELUNDEF;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Apply one relocation.  Returns true for any invalid data.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
relocate (Dwfl_Module * const mod,
Packit Service 97d2fb
          Elf * const relocated,
Packit Service 97d2fb
          struct reloc_symtab_cache * const reloc_symtab,
Packit Service 97d2fb
          Elf_Data * const tdata,
Packit Service 97d2fb
          const GElf_Ehdr * const ehdr,
Packit Service 97d2fb
          GElf_Addr offset,
Packit Service 97d2fb
          const GElf_Sxword *addend,
Packit Service 97d2fb
          int rtype,
Packit Service 97d2fb
          int symndx)
Packit Service 97d2fb
{
Packit Service 97d2fb
    /* First see if this is a reloc we can handle.
Packit Service 97d2fb
       If we are skipping it, don't bother resolving the symbol.  */
Packit Service 97d2fb
Packit Service 97d2fb
    if (unlikely (rtype == 0))
Packit Service 97d2fb
      /* In some odd situations, the linker can leave R_*_NONE relocs
Packit Service 97d2fb
	 behind.  This is probably bogus ld -r behavior, but the only
Packit Service 97d2fb
	 cases it's known to appear in are harmless: DWARF data
Packit Service 97d2fb
	 referring to addresses in a section that has been discarded.
Packit Service 97d2fb
	 So we just pretend it's OK without further relocation.  */
Packit Service 97d2fb
      return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
    int addsub = 0;
Packit Service 97d2fb
    Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype, &addsub);
Packit Service 97d2fb
    if (unlikely (type == ELF_T_NUM))
Packit Service 97d2fb
      return DWFL_E_BADRELTYPE;
Packit Service 97d2fb
Packit Service 97d2fb
    /* First, resolve the symbol to an absolute value.  */
Packit Service 97d2fb
    GElf_Addr value;
Packit Service 97d2fb
Packit Service 97d2fb
    if (symndx == STN_UNDEF)
Packit Service 97d2fb
      /* When strip removes a section symbol referring to a
Packit Service 97d2fb
	 section moved into the debuginfo file, it replaces
Packit Service 97d2fb
	 that symbol index in relocs with STN_UNDEF.  We
Packit Service 97d2fb
	 don't actually need the symbol, because those relocs
Packit Service 97d2fb
	 are always references relative to the nonallocated
Packit Service 97d2fb
	 debugging sections, which start at zero.  */
Packit Service 97d2fb
      value = 0;
Packit Service 97d2fb
    else
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Sym sym;
Packit Service 97d2fb
	GElf_Word shndx;
Packit Service 97d2fb
	Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
Packit Service 97d2fb
					    symndx, &sym, &shndx);
Packit Service 97d2fb
	if (unlikely (error != DWFL_E_NOERROR))
Packit Service 97d2fb
	  return error;
Packit Service 97d2fb
Packit Service 97d2fb
	if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    /* Maybe we can figure it out anyway.  */
Packit Service 97d2fb
	    error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
Packit Service 97d2fb
	    if (error != DWFL_E_NOERROR
Packit Service 97d2fb
		&& !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
Packit Service 97d2fb
	      return error;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	value = sym.st_value;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    /* These are the types we can relocate.  */
Packit Service 97d2fb
#define TYPES		DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);	\
Packit Service 97d2fb
    DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);			\
Packit Service 97d2fb
    DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
Packit Service 97d2fb
    size_t size;
Packit Service 97d2fb
    switch (type)
Packit Service 97d2fb
      {
Packit Service 97d2fb
#define DO_TYPE(NAME, Name)			\
Packit Service 97d2fb
	case ELF_T_##NAME:			\
Packit Service 97d2fb
	  if (addsub != 0 && addend == NULL)	\
Packit Service 97d2fb
	    /* These do not make sense with SHT_REL.  */ \
Packit Service 97d2fb
	    return DWFL_E_BADRELTYPE;		\
Packit Service 97d2fb
	  size = sizeof (GElf_##Name);		\
Packit Service 97d2fb
	break
Packit Service 97d2fb
	TYPES;
Packit Service 97d2fb
#undef DO_TYPE
Packit Service 97d2fb
      default:
Packit Service 97d2fb
	return DWFL_E_BADRELTYPE;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    if (offset > tdata->d_size || tdata->d_size - offset < size)
Packit Service 97d2fb
      return DWFL_E_BADRELOFF;
Packit Service 97d2fb
Packit Service 97d2fb
#define DO_TYPE(NAME, Name) GElf_##Name Name;
Packit Service 97d2fb
    union { TYPES; } tmpbuf;
Packit Service 97d2fb
#undef DO_TYPE
Packit Service 97d2fb
    Elf_Data tmpdata =
Packit Service 97d2fb
      {
Packit Service 97d2fb
	.d_type = type,
Packit Service 97d2fb
	.d_buf = &tmpbuf,
Packit Service 97d2fb
	.d_size = size,
Packit Service 97d2fb
	.d_version = EV_CURRENT,
Packit Service 97d2fb
      };
Packit Service 97d2fb
    Elf_Data rdata =
Packit Service 97d2fb
      {
Packit Service 97d2fb
	.d_type = type,
Packit Service 97d2fb
	.d_buf = tdata->d_buf + offset,
Packit Service 97d2fb
	.d_size = size,
Packit Service 97d2fb
	.d_version = EV_CURRENT,
Packit Service 97d2fb
      };
Packit Service 97d2fb
Packit Service 97d2fb
    /* XXX check for overflow? */
Packit Service 97d2fb
    if (addend)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	/* For the addend form, we have the value already.  */
Packit Service 97d2fb
	value += *addend;
Packit Service 97d2fb
	/* For ADD/SUB relocations we need to fetch the section
Packit Service 97d2fb
	   contents.  */
Packit Service 97d2fb
	if (addsub != 0)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
Packit Service 97d2fb
					 ehdr->e_ident[EI_DATA]);
Packit Service 97d2fb
	    if (d == NULL)
Packit Service 97d2fb
	      return DWFL_E_LIBELF;
Packit Service 97d2fb
	    assert (d == &tmpdata);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	switch (type)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
#define DO_TYPE(NAME, Name)			\
Packit Service 97d2fb
	    case ELF_T_##NAME:			\
Packit Service 97d2fb
	      if (addsub != 0)			\
Packit Service 97d2fb
		tmpbuf.Name += value * addsub;	\
Packit Service 97d2fb
	      else				\
Packit Service 97d2fb
		tmpbuf.Name = value;		\
Packit Service 97d2fb
	    break
Packit Service 97d2fb
	    TYPES;
Packit Service 97d2fb
#undef DO_TYPE
Packit Service 97d2fb
	  default:
Packit Service 97d2fb
	    abort ();
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      }
Packit Service 97d2fb
    else
Packit Service 97d2fb
      {
Packit Service 97d2fb
	/* Extract the original value and apply the reloc.  */
Packit Service 97d2fb
	Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
Packit Service 97d2fb
				     ehdr->e_ident[EI_DATA]);
Packit Service 97d2fb
	if (d == NULL)
Packit Service 97d2fb
	  return DWFL_E_LIBELF;
Packit Service 97d2fb
	assert (d == &tmpdata);
Packit Service 97d2fb
	switch (type)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
#define DO_TYPE(NAME, Name)				\
Packit Service 97d2fb
	    case ELF_T_##NAME:				\
Packit Service 97d2fb
	      tmpbuf.Name += (GElf_##Name) value;	\
Packit Service 97d2fb
	    break
Packit Service 97d2fb
	    TYPES;
Packit Service 97d2fb
#undef DO_TYPE
Packit Service 97d2fb
	  default:
Packit Service 97d2fb
	    abort ();
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    /* Now convert the relocated datum back to the target
Packit Service 97d2fb
       format.  This will write into rdata.d_buf, which
Packit Service 97d2fb
       points into the raw section data being relocated.  */
Packit Service 97d2fb
    Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
Packit Service 97d2fb
				 ehdr->e_ident[EI_DATA]);
Packit Service 97d2fb
    if (s == NULL)
Packit Service 97d2fb
      return DWFL_E_LIBELF;
Packit Service 97d2fb
    assert (s == &rdata);
Packit Service 97d2fb
Packit Service 97d2fb
    /* We have applied this relocation!  */
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline void
Packit Service 97d2fb
check_badreltype (bool *first_badreltype,
Packit Service 97d2fb
                  Dwfl_Module *mod,
Packit Service 97d2fb
                  Dwfl_Error *result)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (*first_badreltype)
Packit Service 97d2fb
    {
Packit Service 97d2fb
       *first_badreltype = false;
Packit Service 97d2fb
       if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
Packit Service 97d2fb
          /* This might be because ebl_openbackend failed to find
Packit Service 97d2fb
             any libebl_CPU.so library.  Diagnose that clearly.  */
Packit Service 97d2fb
          *result = DWFL_E_UNKNOWN_MACHINE;
Packit Service 97d2fb
     }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
Packit Service 97d2fb
		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
Packit Service 97d2fb
		  Elf_Scn *scn, GElf_Shdr *shdr,
Packit Service 97d2fb
		  Elf_Scn *tscn, bool debugscn, bool partial)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* First, fetch the name of the section these relocations apply to.
Packit Service 97d2fb
     Then try to decompress both relocation and target section.  */
Packit Service 97d2fb
  GElf_Shdr tshdr_mem;
Packit Service 97d2fb
  GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
Packit Service 97d2fb
  if (tshdr == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
Packit Service 97d2fb
  if (tname == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
Packit Service 97d2fb
    /* This relocation section is not for a debugging section.
Packit Service 97d2fb
       Nothing to do here.  */
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
Packit Service 97d2fb
    elf_compress_gnu (tscn, 0, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
    if (elf_compress (tscn, 0, 0) < 0)
Packit Service 97d2fb
      return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Reload Shdr in case section was just decompressed.  */
Packit Service 97d2fb
  tshdr = gelf_getshdr (tscn, &tshdr_mem);
Packit Service 97d2fb
  if (tshdr == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (tshdr->sh_type == SHT_NOBITS)
Packit Service 97d2fb
      || unlikely (tshdr->sh_size == 0))
Packit Service 97d2fb
    /* No contents to relocate.  */
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
Packit Service 97d2fb
  if (sname == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
Packit Service 97d2fb
    elf_compress_gnu (scn, 0, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
    if (elf_compress (scn, 0, 0) < 0)
Packit Service 97d2fb
      return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Reload Shdr in case section was just decompressed.  */
Packit Service 97d2fb
  GElf_Shdr shdr_mem;
Packit Service 97d2fb
  shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
  if (shdr == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Fetch the section data that needs the relocations applied.  */
Packit Service 97d2fb
  Elf_Data *tdata = elf_rawdata (tscn, NULL);
Packit Service 97d2fb
  if (tdata == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If either the section that needs the relocation applied, or the
Packit Service 97d2fb
     section that the relocations come from overlap one of the ehdrs,
Packit Service 97d2fb
     shdrs or phdrs data then we refuse to do the relocations.  It
Packit Service 97d2fb
     isn't illegal for ELF section data to overlap the header data,
Packit Service 97d2fb
     but updating the (relocation) data might corrupt the in-memory
Packit Service 97d2fb
     libelf headers causing strange corruptions or errors.
Packit Service 97d2fb
Packit Service 97d2fb
     This is only an issue if the ELF is mmapped and the section data
Packit Service 97d2fb
     comes from the mmapped region (is not malloced or decompressed).
Packit Service 97d2fb
  */
Packit Service 97d2fb
  if (relocated->map_address != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
Packit Service 97d2fb
      if (unlikely (shdr->sh_offset < ehsize
Packit Service 97d2fb
		    || tshdr->sh_offset < ehsize))
Packit Service 97d2fb
	return DWFL_E_BADELF;
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Off shdrs_start = ehdr->e_shoff;
Packit Service 97d2fb
      size_t shnums;
Packit Service 97d2fb
      if (elf_getshdrnum (relocated, &shnums) < 0)
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
      /* Overflows will have been checked by elf_getshdrnum/get|rawdata.  */
Packit Service 97d2fb
      size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
Packit Service 97d2fb
      GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
Packit Service 97d2fb
      if (unlikely (shdrs_start < shdr->sh_offset + shdr->sh_size
Packit Service 97d2fb
		    && shdr->sh_offset < shdrs_end))
Packit Service 97d2fb
	if ((scn->flags & ELF_F_MALLOCED) == 0)
Packit Service 97d2fb
	  return DWFL_E_BADELF;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (shdrs_start < tshdr->sh_offset + tshdr->sh_size
Packit Service 97d2fb
		    && tshdr->sh_offset < shdrs_end))
Packit Service 97d2fb
	if ((tscn->flags & ELF_F_MALLOCED) == 0)
Packit Service 97d2fb
	  return DWFL_E_BADELF;
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Off phdrs_start = ehdr->e_phoff;
Packit Service 97d2fb
      size_t phnums;
Packit Service 97d2fb
      if (elf_getphdrnum (relocated, &phnums) < 0)
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
      if (phdrs_start != 0 && phnums != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Overflows will have been checked by elf_getphdrnum/get|rawdata.  */
Packit Service 97d2fb
	  size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
Packit Service 97d2fb
	  GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
Packit Service 97d2fb
	  if (unlikely (phdrs_start < shdr->sh_offset + shdr->sh_size
Packit Service 97d2fb
			&& shdr->sh_offset < phdrs_end))
Packit Service 97d2fb
	    if ((scn->flags & ELF_F_MALLOCED) == 0)
Packit Service 97d2fb
	      return DWFL_E_BADELF;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (unlikely (phdrs_start < tshdr->sh_offset + tshdr->sh_size
Packit Service 97d2fb
			&& tshdr->sh_offset < phdrs_end))
Packit Service 97d2fb
	    if ((tscn->flags & ELF_F_MALLOCED) == 0)
Packit Service 97d2fb
	      return DWFL_E_BADELF;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Fetch the relocation section and apply each reloc in it.  */
Packit Service 97d2fb
  Elf_Data *reldata = elf_getdata (scn, NULL);
Packit Service 97d2fb
  if (reldata == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Error result = DWFL_E_NOERROR;
Packit Service 97d2fb
  bool first_badreltype = true;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t sh_entsize
Packit Service 97d2fb
    = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
Packit Service 97d2fb
		  1, EV_CURRENT);
Packit Service 97d2fb
  size_t nrels = shdr->sh_size / sh_entsize;
Packit Service 97d2fb
  size_t complete = 0;
Packit Service 97d2fb
  if (shdr->sh_type == SHT_REL)
Packit Service 97d2fb
    for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
Packit Service 97d2fb
	if (r == NULL)
Packit Service 97d2fb
	  return DWFL_E_LIBELF;
Packit Service 97d2fb
	result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
Packit Service 97d2fb
			   r->r_offset, NULL,
Packit Service 97d2fb
			   GELF_R_TYPE (r->r_info),
Packit Service 97d2fb
			   GELF_R_SYM (r->r_info));
Packit Service 97d2fb
	check_badreltype (&first_badreltype, mod, &result);
Packit Service 97d2fb
	if (partial)
Packit Service 97d2fb
	  switch (result)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	    case DWFL_E_NOERROR:
Packit Service 97d2fb
	      /* We applied the relocation.  Elide it.  */
Packit Service 97d2fb
	      memset (&rel_mem, 0, sizeof rel_mem);
Packit Service 97d2fb
	      if (unlikely (gelf_update_rel (reldata, relidx, &rel_mem) == 0))
Packit Service 97d2fb
		return DWFL_E_LIBELF;
Packit Service 97d2fb
	      ++complete;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    case DWFL_E_BADRELTYPE:
Packit Service 97d2fb
	    case DWFL_E_RELUNDEF:
Packit Service 97d2fb
	      /* We couldn't handle this relocation.  Skip it.  */
Packit Service 97d2fb
	      result = DWFL_E_NOERROR;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    default:
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
      }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
Packit Service 97d2fb
					       &rela_mem);
Packit Service 97d2fb
	if (r == NULL)
Packit Service 97d2fb
	  return DWFL_E_LIBELF;
Packit Service 97d2fb
	result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
Packit Service 97d2fb
			   r->r_offset, &r->r_addend,
Packit Service 97d2fb
			   GELF_R_TYPE (r->r_info),
Packit Service 97d2fb
			   GELF_R_SYM (r->r_info));
Packit Service 97d2fb
	check_badreltype (&first_badreltype, mod, &result);
Packit Service 97d2fb
	if (partial)
Packit Service 97d2fb
	  switch (result)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	    case DWFL_E_NOERROR:
Packit Service 97d2fb
	      /* We applied the relocation.  Elide it.  */
Packit Service 97d2fb
	      memset (&rela_mem, 0, sizeof rela_mem);
Packit Service 97d2fb
	      if (unlikely (gelf_update_rela (reldata, relidx,
Packit Service 97d2fb
					      &rela_mem) == 0))
Packit Service 97d2fb
		return DWFL_E_LIBELF;
Packit Service 97d2fb
	      ++complete;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    case DWFL_E_BADRELTYPE:
Packit Service 97d2fb
	    case DWFL_E_RELUNDEF:
Packit Service 97d2fb
	      /* We couldn't handle this relocation.  Skip it.  */
Packit Service 97d2fb
	      result = DWFL_E_NOERROR;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    default:
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  if (likely (result == DWFL_E_NOERROR))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (!partial || complete == nrels)
Packit Service 97d2fb
	/* Mark this relocation section as being empty now that we have
Packit Service 97d2fb
	   done its work.  This affects unstrip -R, so e.g. it emits an
Packit Service 97d2fb
	   empty .rela.debug_info along with a .debug_info that has
Packit Service 97d2fb
	   already been fully relocated.  */
Packit Service 97d2fb
	nrels = 0;
Packit Service 97d2fb
      else if (complete != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We handled some of the relocations but not all.
Packit Service 97d2fb
	     We've zeroed out the ones we processed.
Packit Service 97d2fb
	     Now remove them from the section.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  size_t next = 0;
Packit Service 97d2fb
	  if (shdr->sh_type == SHT_REL)
Packit Service 97d2fb
	    for (size_t relidx = 0; relidx < nrels; ++relidx)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		GElf_Rel rel_mem;
Packit Service 97d2fb
		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
Packit Service 97d2fb
		if (unlikely (r == NULL))
Packit Service 97d2fb
		  return DWFL_E_LIBELF;
Packit Service 97d2fb
		if (r->r_info != 0 || r->r_offset != 0)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (next != relidx)
Packit Service 97d2fb
		      if (unlikely (gelf_update_rel (reldata, next, r) == 0))
Packit Service 97d2fb
			return DWFL_E_LIBELF;
Packit Service 97d2fb
		    ++next;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    for (size_t relidx = 0; relidx < nrels; ++relidx)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		GElf_Rela rela_mem;
Packit Service 97d2fb
		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
Packit Service 97d2fb
		if (unlikely (r == NULL))
Packit Service 97d2fb
		  return DWFL_E_LIBELF;
Packit Service 97d2fb
		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (next != relidx)
Packit Service 97d2fb
		      if (unlikely (gelf_update_rela (reldata, next, r) == 0))
Packit Service 97d2fb
			return DWFL_E_LIBELF;
Packit Service 97d2fb
		    ++next;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	  nrels = next;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      shdr->sh_size = reldata->d_size = nrels * sh_entsize;
Packit Service 97d2fb
      if (unlikely (gelf_update_shdr (scn, shdr) == 0))
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl_Error
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
Packit Service 97d2fb
{
Packit Service 97d2fb
  assert (mod->e_type == ET_REL);
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
  const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
Packit Service 97d2fb
  if (ehdr == NULL)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t d_shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  RELOC_SYMTAB_CACHE (reloc_symtab);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Look at each section in the debuginfo file, and process the
Packit Service 97d2fb
     relocation sections for debugging sections.  */
Packit Service 97d2fb
  Dwfl_Error result = DWFL_E_NOERROR;
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while (result == DWFL_E_NOERROR
Packit Service 97d2fb
	 && (scn = elf_nextscn (debugfile, 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 (unlikely (shdr == NULL))
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
      if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
Packit Service 97d2fb
	  && shdr->sh_size != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* It's a relocation section.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
Packit Service 97d2fb
	  if (unlikely (tscn == NULL))
Packit Service 97d2fb
	    result = DWFL_E_LIBELF;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
Packit Service 97d2fb
				       &reloc_symtab, scn, shdr, tscn,
Packit Service 97d2fb
				       debug, true /* partial always OK. */);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl_Error
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
Packit Service 97d2fb
			    Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
  GElf_Shdr shdr_mem;
Packit Service 97d2fb
Packit Service 97d2fb
  RELOC_SYMTAB_CACHE (reloc_symtab);
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Error result = __libdwfl_module_getebl (mod);
Packit Service 97d2fb
  if (unlikely (result != DWFL_E_NOERROR))
Packit Service 97d2fb
    return result;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr *ehdr = gelf_getehdr (relocated, &ehdr_mem);
Packit Service 97d2fb
  if (unlikely (ehdr == NULL))
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Shdr *shdr = gelf_getshdr (relocscn, &shdr_mem);
Packit Service 97d2fb
  if (unlikely (shdr == NULL))
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  return relocate_section (mod, relocated, ehdr, shstrndx, &reloc_symtab,
Packit Service 97d2fb
			   relocscn, shdr, tscn, false, partial);
Packit Service 97d2fb
}