Home | History | Annotate | Download | only in libdwfl
      1 /* Relocate debug information.
      2    Copyright (C) 2005-2010 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   assert (mod->e_type == ET_REL);
     63 
     64   Elf_Scn *refscn = elf_getscn (elf, shndx);
     65   GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
     66   if (refshdr == NULL)
     67     return DWFL_E_LIBELF;
     68 
     69   if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
     70     {
     71       /* This is a loaded section.  Find its actual
     72 	 address and update the section header.  */
     73 
     74       if (*shstrndx == SHN_UNDEF
     75 	  && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
     76 	return DWFL_E_LIBELF;
     77 
     78       const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
     79       if (unlikely (name == NULL))
     80 	return DWFL_E_LIBELF;
     81 
     82       if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
     83 						    name, shndx, refshdr,
     84 						    &refshdr->sh_addr))
     85 	return CBFAIL;
     86 
     87       if (refshdr->sh_addr == (Dwarf_Addr) -1l)
     88 	/* The callback indicated this section wasn't really loaded but we
     89 	   don't really care.  */
     90 	refshdr->sh_addr = 0;	/* Make no adjustment below.  */
     91 
     92       /* Update the in-core file's section header to show the final
     93 	 load address (or unloadedness).  This serves as a cache,
     94 	 so we won't get here again for the same section.  */
     95       if (likely (refshdr->sh_addr != 0)
     96 	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
     97 	return DWFL_E_LIBELF;
     98     }
     99 
    100   if (refshdr->sh_flags & SHF_ALLOC)
    101     /* Apply the adjustment.  */
    102     *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
    103 
    104   return DWFL_E_NOERROR;
    105 }
    106 
    107 
    108 /* Cache used by relocate_getsym.  */
    109 struct reloc_symtab_cache
    110 {
    111   Elf *symelf;
    112   Elf_Data *symdata;
    113   Elf_Data *symxndxdata;
    114   Elf_Data *symstrdata;
    115   size_t symshstrndx;
    116   size_t strtabndx;
    117 };
    118 #define RELOC_SYMTAB_CACHE(cache)	\
    119   struct reloc_symtab_cache cache =	\
    120     { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
    121 
    122 /* This is just doing dwfl_module_getsym, except that we must always use
    123    the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
    124 static Dwfl_Error
    125 relocate_getsym (Dwfl_Module *mod,
    126 		 Elf *relocated, struct reloc_symtab_cache *cache,
    127 		 int symndx, GElf_Sym *sym, GElf_Word *shndx)
    128 {
    129   if (cache->symdata == NULL)
    130     {
    131       if (mod->symfile == NULL || mod->symfile->elf != relocated)
    132 	{
    133 	  /* We have to look up the symbol table in the file we are
    134 	     relocating, if it has its own.  These reloc sections refer to
    135 	     the symbol table in this file, and a symbol table in the main
    136 	     file might not match.  However, some tools did produce ET_REL
    137 	     .debug files with relocs but no symtab of their own.  */
    138 	  Elf_Scn *scn = NULL;
    139 	  while ((scn = elf_nextscn (relocated, scn)) != NULL)
    140 	    {
    141 	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
    142 	      if (shdr != NULL)
    143 		switch (shdr->sh_type)
    144 		  {
    145 		  default:
    146 		    continue;
    147 		  case SHT_SYMTAB:
    148 		    cache->symelf = relocated;
    149 		    cache->symdata = elf_getdata (scn, NULL);
    150 		    cache->strtabndx = shdr->sh_link;
    151 		    if (unlikely (cache->symdata == NULL))
    152 		      return DWFL_E_LIBELF;
    153 		    break;
    154 		  case SHT_SYMTAB_SHNDX:
    155 		    cache->symxndxdata = elf_getdata (scn, NULL);
    156 		    if (unlikely (cache->symxndxdata == NULL))
    157 		      return DWFL_E_LIBELF;
    158 		    break;
    159 		  }
    160 	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
    161 		break;
    162 	    }
    163 	}
    164       if (cache->symdata == NULL)
    165 	{
    166 	  /* We might not have looked for a symbol table file yet,
    167 	     when coming from __libdwfl_relocate_section.  */
    168 	  if (unlikely (mod->symfile == NULL)
    169 	      && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
    170 	    return dwfl_errno ();
    171 
    172 	  /* The symbol table we have already cached is the one from
    173 	     the file being relocated, so it's what we need.  Or else
    174 	     this is an ET_REL .debug file with no .symtab of its own;
    175 	     the symbols refer to the section indices in the main file.  */
    176 	  cache->symelf = mod->symfile->elf;
    177 	  cache->symdata = mod->symdata;
    178 	  cache->symxndxdata = mod->symxndxdata;
    179 	  cache->symstrdata = mod->symstrdata;
    180 	}
    181     }
    182 
    183   if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
    184 				  symndx, sym, shndx) == NULL))
    185     return DWFL_E_LIBELF;
    186 
    187   if (sym->st_shndx != SHN_XINDEX)
    188     *shndx = sym->st_shndx;
    189 
    190   switch (sym->st_shndx)
    191     {
    192     case SHN_ABS:
    193     case SHN_UNDEF:
    194       return DWFL_E_NOERROR;
    195 
    196     case SHN_COMMON:
    197       sym->st_value = 0;	/* Value is size, not helpful. */
    198       return DWFL_E_NOERROR;
    199     }
    200 
    201   return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
    202 				   *shndx, &sym->st_value);
    203 }
    204 
    205 /* Handle an undefined symbol.  We really only support ET_REL for Linux
    206    kernel modules, and offline archives.  The behavior of the Linux module
    207    loader is very simple and easy to mimic.  It only matches magically
    208    exported symbols, and we match any defined symbols.  But we get the same
    209    answer except when the module's symbols are undefined and would prevent
    210    it from being loaded.  */
    211 static Dwfl_Error
    212 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
    213 		GElf_Sym *sym, GElf_Word shndx)
    214 {
    215   /* First we need its name.  */
    216   if (sym->st_name != 0)
    217     {
    218       if (symtab->symstrdata == NULL)
    219 	{
    220 	  /* Cache the strtab for this symtab.  */
    221 	  assert (referer->symfile == NULL
    222 		  || referer->symfile->elf != symtab->symelf);
    223 	  symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
    224 							symtab->strtabndx),
    225 					    NULL);
    226 	  if (unlikely (symtab->symstrdata == NULL))
    227 	    return DWFL_E_LIBELF;
    228 	}
    229       if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
    230 	return DWFL_E_BADSTROFF;
    231 
    232       const char *name = symtab->symstrdata->d_buf;
    233       name += sym->st_name;
    234 
    235       for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
    236 	if (m != referer)
    237 	  {
    238 	    /* Get this module's symtab.
    239 	       If we got a fresh error reading the table, report it.
    240 	       If we just have no symbols in this module, no harm done.  */
    241 	    if (m->symdata == NULL
    242 		&& m->symerr == DWFL_E_NOERROR
    243 		&& INTUSE(dwfl_module_getsymtab) (m) < 0
    244 		&& m->symerr != DWFL_E_NO_SYMTAB)
    245 	      return m->symerr;
    246 
    247 	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
    248 	      {
    249 		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
    250 					ndx, sym, &shndx);
    251 		if (unlikely (sym == NULL))
    252 		  return DWFL_E_LIBELF;
    253 		if (sym->st_shndx != SHN_XINDEX)
    254 		  shndx = sym->st_shndx;
    255 
    256 		/* We are looking for a defined global symbol with a name.  */
    257 		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
    258 		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
    259 		    || sym->st_name == 0)
    260 		  continue;
    261 
    262 		/* Get this candidate symbol's name.  */
    263 		if (unlikely (sym->st_name >= m->symstrdata->d_size))
    264 		  return DWFL_E_BADSTROFF;
    265 		const char *n = m->symstrdata->d_buf;
    266 		n += sym->st_name;
    267 
    268 		/* Does the name match?  */
    269 		if (strcmp (name, n))
    270 		  continue;
    271 
    272 		/* We found it!  */
    273 		if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
    274 		  return DWFL_E_NOERROR;
    275 
    276 		if (m->e_type != ET_REL)
    277 		  {
    278 		    sym->st_value = dwfl_adjusted_st_value (m, sym->st_value);
    279 		    return DWFL_E_NOERROR;
    280 		  }
    281 
    282 		/* In an ET_REL file, the symbol table values are relative
    283 		   to the section, not to the module's load base.  */
    284 		size_t symshstrndx = SHN_UNDEF;
    285 		return __libdwfl_relocate_value (m, m->symfile->elf,
    286 						 &symshstrndx,
    287 						 shndx, &sym->st_value);
    288 	      }
    289 	  }
    290     }
    291 
    292   return DWFL_E_RELUNDEF;
    293 }
    294 
    295 static Dwfl_Error
    296 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
    297 		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
    298 		  Elf_Scn *scn, GElf_Shdr *shdr,
    299 		  Elf_Scn *tscn, bool debugscn, bool partial)
    300 {
    301   /* First, fetch the name of the section these relocations apply to.  */
    302   GElf_Shdr tshdr_mem;
    303   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
    304   const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
    305   if (tname == NULL)
    306     return DWFL_E_LIBELF;
    307 
    308   if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
    309     /* No contents to relocate.  */
    310     return DWFL_E_NOERROR;
    311 
    312   if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
    313     /* This relocation section is not for a debugging section.
    314        Nothing to do here.  */
    315     return DWFL_E_NOERROR;
    316 
    317   /* Fetch the section data that needs the relocations applied.  */
    318   Elf_Data *tdata = elf_rawdata (tscn, NULL);
    319   if (tdata == NULL)
    320     return DWFL_E_LIBELF;
    321 
    322   /* Apply one relocation.  Returns true for any invalid data.  */
    323   Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
    324 		       int rtype, int symndx)
    325   {
    326     /* First see if this is a reloc we can handle.
    327        If we are skipping it, don't bother resolving the symbol.  */
    328 
    329     if (unlikely (rtype == 0))
    330       /* In some odd situations, the linker can leave R_*_NONE relocs
    331 	 behind.  This is probably bogus ld -r behavior, but the only
    332 	 cases it's known to appear in are harmless: DWARF data
    333 	 referring to addresses in a section that has been discarded.
    334 	 So we just pretend it's OK without further relocation.  */
    335       return DWFL_E_NOERROR;
    336 
    337     Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
    338     if (unlikely (type == ELF_T_NUM))
    339       return DWFL_E_BADRELTYPE;
    340 
    341     /* First, resolve the symbol to an absolute value.  */
    342     GElf_Addr value;
    343 
    344     if (symndx == STN_UNDEF)
    345       /* When strip removes a section symbol referring to a
    346 	 section moved into the debuginfo file, it replaces
    347 	 that symbol index in relocs with STN_UNDEF.  We
    348 	 don't actually need the symbol, because those relocs
    349 	 are always references relative to the nonallocated
    350 	 debugging sections, which start at zero.  */
    351       value = 0;
    352     else
    353       {
    354 	GElf_Sym sym;
    355 	GElf_Word shndx;
    356 	Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
    357 					    symndx, &sym, &shndx);
    358 	if (unlikely (error != DWFL_E_NOERROR))
    359 	  return error;
    360 
    361 	if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
    362 	  {
    363 	    /* Maybe we can figure it out anyway.  */
    364 	    error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
    365 	    if (error != DWFL_E_NOERROR
    366 		&& !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
    367 	      return error;
    368 	  }
    369 
    370 	value = sym.st_value;
    371       }
    372 
    373     /* These are the types we can relocate.  */
    374 #define TYPES		DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);	\
    375     DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);			\
    376     DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
    377     size_t size;
    378     switch (type)
    379       {
    380 #define DO_TYPE(NAME, Name)			\
    381 	case ELF_T_##NAME:			\
    382 	  size = sizeof (GElf_##Name);		\
    383 	break
    384 	TYPES;
    385 #undef DO_TYPE
    386       default:
    387 	return DWFL_E_BADRELTYPE;
    388       }
    389 
    390     if (offset + size > tdata->d_size)
    391       return DWFL_E_BADRELOFF;
    392 
    393 #define DO_TYPE(NAME, Name) GElf_##Name Name;
    394     union { TYPES; } tmpbuf;
    395 #undef DO_TYPE
    396     Elf_Data tmpdata =
    397       {
    398 	.d_type = type,
    399 	.d_buf = &tmpbuf,
    400 	.d_size = size,
    401 	.d_version = EV_CURRENT,
    402       };
    403     Elf_Data rdata =
    404       {
    405 	.d_type = type,
    406 	.d_buf = tdata->d_buf + offset,
    407 	.d_size = size,
    408 	.d_version = EV_CURRENT,
    409       };
    410 
    411     /* XXX check for overflow? */
    412     if (addend)
    413       {
    414 	/* For the addend form, we have the value already.  */
    415 	value += *addend;
    416 	switch (type)
    417 	  {
    418 #define DO_TYPE(NAME, Name)			\
    419 	    case ELF_T_##NAME:			\
    420 	      tmpbuf.Name = value;		\
    421 	    break
    422 	    TYPES;
    423 #undef DO_TYPE
    424 	  default:
    425 	    abort ();
    426 	  }
    427       }
    428     else
    429       {
    430 	/* Extract the original value and apply the reloc.  */
    431 	Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
    432 				     ehdr->e_ident[EI_DATA]);
    433 	if (d == NULL)
    434 	  return DWFL_E_LIBELF;
    435 	assert (d == &tmpdata);
    436 	switch (type)
    437 	  {
    438 #define DO_TYPE(NAME, Name)				\
    439 	    case ELF_T_##NAME:				\
    440 	      tmpbuf.Name += (GElf_##Name) value;	\
    441 	    break
    442 	    TYPES;
    443 #undef DO_TYPE
    444 	  default:
    445 	    abort ();
    446 	  }
    447       }
    448 
    449     /* Now convert the relocated datum back to the target
    450        format.  This will write into rdata.d_buf, which
    451        points into the raw section data being relocated.  */
    452     Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
    453 				 ehdr->e_ident[EI_DATA]);
    454     if (s == NULL)
    455       return DWFL_E_LIBELF;
    456     assert (s == &rdata);
    457 
    458     /* We have applied this relocation!  */
    459     return DWFL_E_NOERROR;
    460   }
    461 
    462   /* Fetch the relocation section and apply each reloc in it.  */
    463   Elf_Data *reldata = elf_getdata (scn, NULL);
    464   if (reldata == NULL)
    465     return DWFL_E_LIBELF;
    466 
    467   Dwfl_Error result = DWFL_E_NOERROR;
    468   bool first_badreltype = true;
    469   inline void check_badreltype (void)
    470   {
    471     if (first_badreltype)
    472       {
    473 	first_badreltype = false;
    474 	if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
    475 	  /* This might be because ebl_openbackend failed to find
    476 	     any libebl_CPU.so library.  Diagnose that clearly.  */
    477 	  result = DWFL_E_UNKNOWN_MACHINE;
    478       }
    479   }
    480 
    481   size_t nrels = shdr->sh_size / shdr->sh_entsize;
    482   size_t complete = 0;
    483   if (shdr->sh_type == SHT_REL)
    484     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    485       {
    486 	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
    487 	if (r == NULL)
    488 	  return DWFL_E_LIBELF;
    489 	result = relocate (r->r_offset, NULL,
    490 			   GELF_R_TYPE (r->r_info),
    491 			   GELF_R_SYM (r->r_info));
    492 	check_badreltype ();
    493 	if (partial)
    494 	  switch (result)
    495 	    {
    496 	    case DWFL_E_NOERROR:
    497 	      /* We applied the relocation.  Elide it.  */
    498 	      memset (&rel_mem, 0, sizeof rel_mem);
    499 	      gelf_update_rel (reldata, relidx, &rel_mem);
    500 	      ++complete;
    501 	      break;
    502 	    case DWFL_E_BADRELTYPE:
    503 	    case DWFL_E_RELUNDEF:
    504 	      /* We couldn't handle this relocation.  Skip it.  */
    505 	      result = DWFL_E_NOERROR;
    506 	      break;
    507 	    default:
    508 	      break;
    509 	    }
    510       }
    511   else
    512     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    513       {
    514 	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
    515 					       &rela_mem);
    516 	if (r == NULL)
    517 	  return DWFL_E_LIBELF;
    518 	result = relocate (r->r_offset, &r->r_addend,
    519 			   GELF_R_TYPE (r->r_info),
    520 			   GELF_R_SYM (r->r_info));
    521 	check_badreltype ();
    522 	if (partial)
    523 	  switch (result)
    524 	    {
    525 	    case DWFL_E_NOERROR:
    526 	      /* We applied the relocation.  Elide it.  */
    527 	      memset (&rela_mem, 0, sizeof rela_mem);
    528 	      gelf_update_rela (reldata, relidx, &rela_mem);
    529 	      ++complete;
    530 	      break;
    531 	    case DWFL_E_BADRELTYPE:
    532 	    case DWFL_E_RELUNDEF:
    533 	      /* We couldn't handle this relocation.  Skip it.  */
    534 	      result = DWFL_E_NOERROR;
    535 	      break;
    536 	    default:
    537 	      break;
    538 	    }
    539       }
    540 
    541   if (likely (result == DWFL_E_NOERROR))
    542     {
    543       if (!partial || complete == nrels)
    544 	/* Mark this relocation section as being empty now that we have
    545 	   done its work.  This affects unstrip -R, so e.g. it emits an
    546 	   empty .rela.debug_info along with a .debug_info that has
    547 	   already been fully relocated.  */
    548 	nrels = 0;
    549       else if (complete != 0)
    550 	{
    551 	  /* We handled some of the relocations but not all.
    552 	     We've zeroed out the ones we processed.
    553 	     Now remove them from the section.  */
    554 
    555 	  size_t next = 0;
    556 	  if (shdr->sh_type == SHT_REL)
    557 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    558 	      {
    559 		GElf_Rel rel_mem;
    560 		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
    561 		if (r->r_info != 0 || r->r_offset != 0)
    562 		  {
    563 		    if (next != relidx)
    564 		      gelf_update_rel (reldata, next, r);
    565 		    ++next;
    566 		  }
    567 	      }
    568 	  else
    569 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    570 	      {
    571 		GElf_Rela rela_mem;
    572 		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
    573 		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
    574 		  {
    575 		    if (next != relidx)
    576 		      gelf_update_rela (reldata, next, r);
    577 		    ++next;
    578 		  }
    579 	      }
    580 	  nrels = next;
    581 	}
    582 
    583       shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
    584       gelf_update_shdr (scn, shdr);
    585     }
    586 
    587   return result;
    588 }
    589 
    590 Dwfl_Error
    591 internal_function
    592 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
    593 {
    594   assert (mod->e_type == ET_REL);
    595 
    596   GElf_Ehdr ehdr_mem;
    597   const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
    598   if (ehdr == NULL)
    599     return DWFL_E_LIBELF;
    600 
    601   size_t d_shstrndx;
    602   if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
    603     return DWFL_E_LIBELF;
    604 
    605   RELOC_SYMTAB_CACHE (reloc_symtab);
    606 
    607   /* Look at each section in the debuginfo file, and process the
    608      relocation sections for debugging sections.  */
    609   Dwfl_Error result = DWFL_E_NOERROR;
    610   Elf_Scn *scn = NULL;
    611   while (result == DWFL_E_NOERROR
    612 	 && (scn = elf_nextscn (debugfile, scn)) != NULL)
    613     {
    614       GElf_Shdr shdr_mem;
    615       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    616 
    617       if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
    618 	  && shdr->sh_size != 0)
    619 	{
    620 	  /* It's a relocation section.  */
    621 
    622 	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
    623 	  if (unlikely (tscn == NULL))
    624 	    result = DWFL_E_LIBELF;
    625 	  else
    626 	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
    627 				       &reloc_symtab, scn, shdr, tscn,
    628 				       debug, !debug);
    629 	}
    630     }
    631 
    632   return result;
    633 }
    634 
    635 Dwfl_Error
    636 internal_function
    637 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
    638 			    Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
    639 {
    640   GElf_Ehdr ehdr_mem;
    641   GElf_Shdr shdr_mem;
    642 
    643   RELOC_SYMTAB_CACHE (reloc_symtab);
    644 
    645   size_t shstrndx;
    646   if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
    647     return DWFL_E_LIBELF;
    648 
    649   return (__libdwfl_module_getebl (mod)
    650 	  ?: relocate_section (mod, relocated,
    651 			       gelf_getehdr (relocated, &ehdr_mem), shstrndx,
    652 			       &reloc_symtab,
    653 			       relocscn, gelf_getshdr (relocscn, &shdr_mem),
    654 			       tscn, false, partial));
    655 }
    656