Home | History | Annotate | Download | only in libdwfl
      1 /* Relocate debug information.
      2    Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    In addition, as a special exception, Red Hat, Inc. gives You the
     19    additional right to link the code of Red Hat elfutils with code licensed
     20    under any Open Source Initiative certified open source license
     21    (http://www.opensource.org/licenses/index.php) which requires the
     22    distribution of source code with any binary distribution and to
     23    distribute linked combinations of the two.  Non-GPL Code permitted under
     24    this exception must only link to the code of Red Hat elfutils through
     25    those well defined interfaces identified in the file named EXCEPTION
     26    found in the source code files (the "Approved Interfaces").  The files
     27    of Non-GPL Code may instantiate templates or use macros or inline
     28    functions from the Approved Interfaces without causing the resulting
     29    work to be covered by the GNU General Public License.  Only Red Hat,
     30    Inc. may make changes or additions to the list of Approved Interfaces.
     31    Red Hat's grant of this exception is conditioned upon your not adding
     32    any new exceptions.  If you wish to add a new Approved Interface or
     33    exception, please contact Red Hat.  You must obey the GNU General Public
     34    License in all respects for all of the Red Hat elfutils code and other
     35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     36    covered by this exception.  If you modify this file, you may extend this
     37    exception to your version of the file, but you are not obligated to do
     38    so.  If you do not wish to provide this exception without modification,
     39    you must delete this exception statement from your version and license
     40    this file solely under the GPL without exception.
     41 
     42    Red Hat elfutils is an included package of the Open Invention Network.
     43    An included package of the Open Invention Network is a package for which
     44    Open Invention Network licensees cross-license their patents.  No patent
     45    license is granted, either expressly or impliedly, by designation as an
     46    included package.  Should you wish to participate in the Open Invention
     47    Network licensing program, please visit www.openinventionnetwork.com
     48    <http://www.openinventionnetwork.com>.  */
     49 
     50 #include "libdwflP.h"
     51 
     52 typedef uint8_t GElf_Byte;
     53 
     54 /* Adjust *VALUE to add the load address of the SHNDX section.
     55    We update the section header in place to cache the result.  */
     56 
     57 Dwfl_Error
     58 internal_function
     59 __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
     60 			  Elf32_Word shndx, GElf_Addr *value)
     61 {
     62   Elf_Scn *refscn = elf_getscn (elf, shndx);
     63   GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
     64   if (refshdr == NULL)
     65     return DWFL_E_LIBELF;
     66 
     67   if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
     68     {
     69       /* This is a loaded section.  Find its actual
     70 	 address and update the section header.  */
     71 
     72       if (*shstrndx == SHN_UNDEF
     73 	  && unlikely (elf_getshstrndx (elf, shstrndx) < 0))
     74 	return DWFL_E_LIBELF;
     75 
     76       const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
     77       if (unlikely (name == NULL))
     78 	return DWFL_E_LIBELF;
     79 
     80       if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
     81 						    name, shndx, refshdr,
     82 						    &refshdr->sh_addr))
     83 	return CBFAIL;
     84 
     85       if (refshdr->sh_addr == (Dwarf_Addr) -1l)
     86 	/* The callback indicated this section wasn't really loaded but we
     87 	   don't really care.  */
     88 	refshdr->sh_addr = 0;	/* Make no adjustment below.  */
     89 
     90       /* Update the in-core file's section header to show the final
     91 	 load address (or unloadedness).  This serves as a cache,
     92 	 so we won't get here again for the same section.  */
     93       if (likely (refshdr->sh_addr != 0)
     94 	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
     95 	return DWFL_E_LIBELF;
     96     }
     97 
     98   /* Apply the adjustment.  */
     99   *value += refshdr->sh_addr;
    100   return DWFL_E_NOERROR;
    101 }
    102 
    103 
    104 /* Cache used by relocate_getsym.  */
    105 struct reloc_symtab_cache
    106 {
    107   Elf *symelf;
    108   Elf_Data *symdata;
    109   Elf_Data *symxndxdata;
    110   Elf_Data *symstrdata;
    111   size_t symshstrndx;
    112   size_t strtabndx;
    113 };
    114 #define RELOC_SYMTAB_CACHE(cache)	\
    115   struct reloc_symtab_cache cache =	\
    116     { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
    117 
    118 /* This is just doing dwfl_module_getsym, except that we must always use
    119    the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
    120 static Dwfl_Error
    121 relocate_getsym (Dwfl_Module *mod,
    122 		 Elf *relocated, struct reloc_symtab_cache *cache,
    123 		 int symndx, GElf_Sym *sym, GElf_Word *shndx)
    124 {
    125   if (cache->symdata == NULL)
    126     {
    127       if (mod->symfile == NULL || mod->symfile->elf != relocated)
    128 	{
    129 	  /* We have to look up the symbol table in the file we are
    130 	     relocating, if it has its own.  These reloc sections refer to
    131 	     the symbol table in this file, and a symbol table in the main
    132 	     file might not match.  However, some tools did produce ET_REL
    133 	     .debug files with relocs but no symtab of their own.  */
    134 	  Elf_Scn *scn = NULL;
    135 	  while ((scn = elf_nextscn (relocated, scn)) != NULL)
    136 	    {
    137 	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
    138 	      if (shdr != NULL)
    139 		switch (shdr->sh_type)
    140 		  {
    141 		  default:
    142 		    continue;
    143 		  case SHT_SYMTAB:
    144 		    cache->symelf = relocated;
    145 		    cache->symdata = elf_getdata (scn, NULL);
    146 		    cache->strtabndx = shdr->sh_link;
    147 		    if (unlikely (cache->symdata == NULL))
    148 		      return DWFL_E_LIBELF;
    149 		    break;
    150 		  case SHT_SYMTAB_SHNDX:
    151 		    cache->symxndxdata = elf_getdata (scn, NULL);
    152 		    if (unlikely (cache->symxndxdata == NULL))
    153 		      return DWFL_E_LIBELF;
    154 		    break;
    155 		  }
    156 	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
    157 		break;
    158 	    }
    159 	}
    160       if (cache->symdata == NULL)
    161 	{
    162 	  /* We might not have looked for a symbol table file yet,
    163 	     when coming from __libdwfl_relocate_section.  */
    164 	  if (unlikely (mod->symfile == NULL)
    165 	      && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
    166 	    return dwfl_errno ();
    167 
    168 	  /* The symbol table we have already cached is the one from
    169 	     the file being relocated, so it's what we need.  Or else
    170 	     this is an ET_REL .debug file with no .symtab of its own;
    171 	     the symbols refer to the section indices in the main file.  */
    172 	  cache->symelf = mod->symfile->elf;
    173 	  cache->symdata = mod->symdata;
    174 	  cache->symxndxdata = mod->symxndxdata;
    175 	  cache->symstrdata = mod->symstrdata;
    176 	}
    177     }
    178 
    179   if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
    180 				  symndx, sym, shndx) == NULL))
    181     return DWFL_E_LIBELF;
    182 
    183   if (sym->st_shndx != SHN_XINDEX)
    184     *shndx = sym->st_shndx;
    185 
    186   switch (*shndx)
    187     {
    188     case SHN_ABS:
    189     case SHN_UNDEF:
    190     case SHN_COMMON:
    191       return DWFL_E_NOERROR;
    192     }
    193 
    194   return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
    195 				   *shndx, &sym->st_value);
    196 }
    197 
    198 /* Handle an undefined symbol.  We really only support ET_REL for Linux
    199    kernel modules, and offline archives.  The behavior of the Linux module
    200    loader is very simple and easy to mimic.  It only matches magically
    201    exported symbols, and we match any defined symbols.  But we get the same
    202    answer except when the module's symbols are undefined and would prevent
    203    it from being loaded.  */
    204 static Dwfl_Error
    205 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
    206 		GElf_Sym *sym, GElf_Word shndx)
    207 {
    208   /* First we need its name.  */
    209   if (sym->st_name != 0)
    210     {
    211       if (symtab->symstrdata == NULL)
    212 	{
    213 	  /* Cache the strtab for this symtab.  */
    214 	  assert (referer->symfile == NULL
    215 		  || referer->symfile->elf != symtab->symelf);
    216 	  symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
    217 							symtab->strtabndx),
    218 					    NULL);
    219 	  if (unlikely (symtab->symstrdata == NULL))
    220 	    return DWFL_E_LIBELF;
    221 	}
    222       if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
    223 	return DWFL_E_BADSTROFF;
    224 
    225       const char *name = symtab->symstrdata->d_buf;
    226       name += sym->st_name;
    227 
    228       for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
    229 	if (m != referer)
    230 	  {
    231 	    /* Get this module's symtab.
    232 	       If we got a fresh error reading the table, report it.
    233 	       If we just have no symbols in this module, no harm done.  */
    234 	    if (m->symdata == NULL
    235 		&& m->symerr == DWFL_E_NOERROR
    236 		&& INTUSE(dwfl_module_getsymtab) (m) < 0
    237 		&& m->symerr != DWFL_E_NO_SYMTAB)
    238 	      return m->symerr;
    239 
    240 	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
    241 	      {
    242 		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
    243 					ndx, sym, &shndx);
    244 		if (unlikely (sym == NULL))
    245 		  return DWFL_E_LIBELF;
    246 		if (sym->st_shndx != SHN_XINDEX)
    247 		  shndx = sym->st_shndx;
    248 
    249 		/* We are looking for a defined global symbol with a name.  */
    250 		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
    251 		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
    252 		    || sym->st_name == 0)
    253 		  continue;
    254 
    255 		/* Get this candidate symbol's name.  */
    256 		if (unlikely (sym->st_name >= m->symstrdata->d_size))
    257 		  return DWFL_E_BADSTROFF;
    258 		const char *n = m->symstrdata->d_buf;
    259 		n += sym->st_name;
    260 
    261 		/* Does the name match?  */
    262 		if (strcmp (name, n))
    263 		  continue;
    264 
    265 		/* We found it!  */
    266 		if (shndx == SHN_ABS)
    267 		  return DWFL_E_NOERROR;
    268 
    269 		/* In an ET_REL file, the symbol table values are relative
    270 		   to the section, not to the module's load base.  */
    271 		size_t symshstrndx = SHN_UNDEF;
    272 		return __libdwfl_relocate_value (m, m->symfile->elf,
    273 						 &symshstrndx,
    274 						 shndx, &sym->st_value);
    275 	      }
    276 	  }
    277     }
    278 
    279   return DWFL_E_RELUNDEF;
    280 }
    281 
    282 static Dwfl_Error
    283 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
    284 		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
    285 		  Elf_Scn *scn, GElf_Shdr *shdr,
    286 		  Elf_Scn *tscn, bool debugscn, bool partial)
    287 {
    288   /* First, fetch the name of the section these relocations apply to.  */
    289   GElf_Shdr tshdr_mem;
    290   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
    291   const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
    292   if (tname == NULL)
    293     return DWFL_E_LIBELF;
    294 
    295   if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
    296     /* This relocation section is not for a debugging section.
    297        Nothing to do here.  */
    298     return DWFL_E_NOERROR;
    299 
    300   /* Fetch the section data that needs the relocations applied.  */
    301   Elf_Data *tdata = elf_rawdata (tscn, NULL);
    302   if (tdata == NULL)
    303     return DWFL_E_LIBELF;
    304 
    305   /* Apply one relocation.  Returns true for any invalid data.  */
    306   Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
    307 		       int rtype, int symndx)
    308   {
    309     /* First see if this is a reloc we can handle.
    310        If we are skipping it, don't bother resolving the symbol.  */
    311     Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
    312     if (unlikely (type == ELF_T_NUM))
    313       return DWFL_E_BADRELTYPE;
    314 
    315     /* First, resolve the symbol to an absolute value.  */
    316     GElf_Addr value;
    317 
    318     if (symndx == STN_UNDEF)
    319       /* When strip removes a section symbol referring to a
    320 	 section moved into the debuginfo file, it replaces
    321 	 that symbol index in relocs with STN_UNDEF.  We
    322 	 don't actually need the symbol, because those relocs
    323 	 are always references relative to the nonallocated
    324 	 debugging sections, which start at zero.  */
    325       value = 0;
    326     else
    327       {
    328 	GElf_Sym sym;
    329 	GElf_Word shndx;
    330 	Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
    331 					    symndx, &sym, &shndx);
    332 	if (unlikely (error != DWFL_E_NOERROR))
    333 	  return error;
    334 
    335 	if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
    336 	  {
    337 	    /* Maybe we can figure it out anyway.  */
    338 	    error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
    339 	    if (error != DWFL_E_NOERROR)
    340 	      return error;
    341 	  }
    342 
    343 	value = sym.st_value;
    344       }
    345 
    346     /* These are the types we can relocate.  */
    347 #define TYPES		DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);	\
    348     DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);			\
    349     DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
    350     size_t size;
    351     switch (type)
    352       {
    353 #define DO_TYPE(NAME, Name)			\
    354 	case ELF_T_##NAME:			\
    355 	  size = sizeof (GElf_##Name);		\
    356 	break
    357 	TYPES;
    358 #undef DO_TYPE
    359       default:
    360 	return DWFL_E_BADRELTYPE;
    361       }
    362 
    363     if (offset + size > tdata->d_size)
    364       return DWFL_E_BADRELOFF;
    365 
    366 #define DO_TYPE(NAME, Name) GElf_##Name Name;
    367     union { TYPES; } tmpbuf;
    368 #undef DO_TYPE
    369     Elf_Data tmpdata =
    370       {
    371 	.d_type = type,
    372 	.d_buf = &tmpbuf,
    373 	.d_size = size,
    374 	.d_version = EV_CURRENT,
    375       };
    376     Elf_Data rdata =
    377       {
    378 	.d_type = type,
    379 	.d_buf = tdata->d_buf + offset,
    380 	.d_size = size,
    381 	.d_version = EV_CURRENT,
    382       };
    383 
    384     /* XXX check for overflow? */
    385     if (addend)
    386       {
    387 	/* For the addend form, we have the value already.  */
    388 	value += *addend;
    389 	switch (type)
    390 	  {
    391 #define DO_TYPE(NAME, Name)			\
    392 	    case ELF_T_##NAME:			\
    393 	      tmpbuf.Name = value;		\
    394 	    break
    395 	    TYPES;
    396 #undef DO_TYPE
    397 	  default:
    398 	    abort ();
    399 	  }
    400       }
    401     else
    402       {
    403 	/* Extract the original value and apply the reloc.  */
    404 	Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
    405 				     ehdr->e_ident[EI_DATA]);
    406 	if (d == NULL)
    407 	  return DWFL_E_LIBELF;
    408 	assert (d == &tmpdata);
    409 	switch (type)
    410 	  {
    411 #define DO_TYPE(NAME, Name)				\
    412 	    case ELF_T_##NAME:				\
    413 	      tmpbuf.Name += (GElf_##Name) value;	\
    414 	    break
    415 	    TYPES;
    416 #undef DO_TYPE
    417 	  default:
    418 	    abort ();
    419 	  }
    420       }
    421 
    422     /* Now convert the relocated datum back to the target
    423        format.  This will write into rdata.d_buf, which
    424        points into the raw section data being relocated.  */
    425     Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
    426 				 ehdr->e_ident[EI_DATA]);
    427     if (s == NULL)
    428       return DWFL_E_LIBELF;
    429     assert (s == &rdata);
    430 
    431     /* We have applied this relocation!  */
    432     return DWFL_E_NOERROR;
    433   }
    434 
    435   /* Fetch the relocation section and apply each reloc in it.  */
    436   Elf_Data *reldata = elf_getdata (scn, NULL);
    437   if (reldata == NULL)
    438     return DWFL_E_LIBELF;
    439 
    440   Dwfl_Error result = DWFL_E_NOERROR;
    441   bool first_badreltype = true;
    442   inline void check_badreltype (void)
    443   {
    444     if (first_badreltype)
    445       {
    446 	first_badreltype = false;
    447 	if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
    448 	  /* This might be because ebl_openbackend failed to find
    449 	     any libebl_CPU.so library.  Diagnose that clearly.  */
    450 	  result = DWFL_E_UNKNOWN_MACHINE;
    451       }
    452   }
    453 
    454   size_t nrels = shdr->sh_size / shdr->sh_entsize;
    455   size_t complete = 0;
    456   if (shdr->sh_type == SHT_REL)
    457     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    458       {
    459 	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
    460 	if (r == NULL)
    461 	  return DWFL_E_LIBELF;
    462 	result = relocate (r->r_offset, NULL,
    463 			   GELF_R_TYPE (r->r_info),
    464 			   GELF_R_SYM (r->r_info));
    465 	check_badreltype ();
    466 	if (partial)
    467 	  switch (result)
    468 	    {
    469 	    case DWFL_E_NOERROR:
    470 	      /* We applied the relocation.  Elide it.  */
    471 	      memset (&rel_mem, 0, sizeof rel_mem);
    472 	      gelf_update_rel (reldata, relidx, &rel_mem);
    473 	      ++complete;
    474 	      break;
    475 	    case DWFL_E_BADRELTYPE:
    476 	    case DWFL_E_RELUNDEF:
    477 	      /* We couldn't handle this relocation.  Skip it.  */
    478 	      result = DWFL_E_NOERROR;
    479 	      break;
    480 	    default:
    481 	      break;
    482 	    }
    483       }
    484   else
    485     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    486       {
    487 	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
    488 					       &rela_mem);
    489 	if (r == NULL)
    490 	  return DWFL_E_LIBELF;
    491 	result = relocate (r->r_offset, &r->r_addend,
    492 			   GELF_R_TYPE (r->r_info),
    493 			   GELF_R_SYM (r->r_info));
    494 	check_badreltype ();
    495 	if (partial)
    496 	  switch (result)
    497 	    {
    498 	    case DWFL_E_NOERROR:
    499 	      /* We applied the relocation.  Elide it.  */
    500 	      memset (&rela_mem, 0, sizeof rela_mem);
    501 	      gelf_update_rela (reldata, relidx, &rela_mem);
    502 	      ++complete;
    503 	      break;
    504 	    case DWFL_E_BADRELTYPE:
    505 	    case DWFL_E_RELUNDEF:
    506 	      /* We couldn't handle this relocation.  Skip it.  */
    507 	      result = DWFL_E_NOERROR;
    508 	      break;
    509 	    default:
    510 	      break;
    511 	    }
    512       }
    513 
    514   if (likely (result == DWFL_E_NOERROR))
    515     {
    516       if (!partial || complete == nrels)
    517 	/* Mark this relocation section as being empty now that we have
    518 	   done its work.  This affects unstrip -R, so e.g. it emits an
    519 	   empty .rela.debug_info along with a .debug_info that has
    520 	   already been fully relocated.  */
    521 	nrels = 0;
    522       else if (complete != 0)
    523 	{
    524 	  /* We handled some of the relocations but not all.
    525 	     We've zeroed out the ones we processed.
    526 	     Now remove them from the section.  */
    527 
    528 	  size_t next = 0;
    529 	  if (shdr->sh_type == SHT_REL)
    530 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    531 	      {
    532 		GElf_Rel rel_mem;
    533 		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
    534 		if (r->r_info != 0 || r->r_offset != 0)
    535 		  {
    536 		    if (next != relidx)
    537 		      gelf_update_rel (reldata, next, r);
    538 		    ++next;
    539 		  }
    540 	      }
    541 	  else
    542 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    543 	      {
    544 		GElf_Rela rela_mem;
    545 		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
    546 		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
    547 		  {
    548 		    if (next != relidx)
    549 		      gelf_update_rela (reldata, next, r);
    550 		    ++next;
    551 		  }
    552 	      }
    553 	  nrels = next;
    554 	}
    555 
    556       shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
    557       gelf_update_shdr (scn, shdr);
    558     }
    559 
    560   return result;
    561 }
    562 
    563 Dwfl_Error
    564 internal_function
    565 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
    566 {
    567   assert (mod->e_type == ET_REL);
    568 
    569   GElf_Ehdr ehdr_mem;
    570   const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
    571   if (ehdr == NULL)
    572     return DWFL_E_LIBELF;
    573 
    574   size_t d_shstrndx;
    575   if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
    576     return DWFL_E_LIBELF;
    577 
    578   RELOC_SYMTAB_CACHE (reloc_symtab);
    579 
    580   /* Look at each section in the debuginfo file, and process the
    581      relocation sections for debugging sections.  */
    582   Dwfl_Error result = DWFL_E_NOERROR;
    583   Elf_Scn *scn = NULL;
    584   while (result == DWFL_E_NOERROR
    585 	 && (scn = elf_nextscn (debugfile, scn)) != NULL)
    586     {
    587       GElf_Shdr shdr_mem;
    588       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    589 
    590       if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
    591 	  && shdr->sh_size != 0)
    592 	{
    593 	  /* It's a relocation section.  */
    594 
    595 	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
    596 	  if (unlikely (tscn == NULL))
    597 	    result = DWFL_E_LIBELF;
    598 	  else
    599 	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
    600 				       &reloc_symtab, scn, shdr, tscn,
    601 				       debug, !debug);
    602 	}
    603     }
    604 
    605   return result;
    606 }
    607 
    608 Dwfl_Error
    609 internal_function
    610 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
    611 			    Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
    612 {
    613   GElf_Ehdr ehdr_mem;
    614   GElf_Shdr shdr_mem;
    615 
    616   RELOC_SYMTAB_CACHE (reloc_symtab);
    617 
    618   size_t shstrndx;
    619   if (elf_getshstrndx (relocated, &shstrndx) < 0)
    620     return DWFL_E_LIBELF;
    621 
    622   return (__libdwfl_module_getebl (mod)
    623 	  ?: relocate_section (mod, relocated,
    624 			       gelf_getehdr (relocated, &ehdr_mem), shstrndx,
    625 			       &reloc_symtab,
    626 			       relocscn, gelf_getshdr (relocscn, &shdr_mem),
    627 			       tscn, false, partial));
    628 }
    629