Home | History | Annotate | Download | only in libdwfl
      1 /* Relocate debug information.
      2    Copyright (C) 2005-2011, 2014, 2016, 2018 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      8      * the GNU Lesser General Public License as published by the Free
      9        Software Foundation; either version 3 of the License, or (at
     10        your option) any later version
     11 
     12    or
     13 
     14      * the GNU General Public License as published by the Free
     15        Software Foundation; either version 2 of the License, or (at
     16        your option) any later version
     17 
     18    or both in parallel, as here.
     19 
     20    elfutils is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received copies of the GNU General Public License and
     26    the GNU Lesser General Public License along with this program.  If
     27    not, see <http://www.gnu.org/licenses/>.  */
     28 
     29 #ifdef HAVE_CONFIG_H
     30 # include <config.h>
     31 #endif
     32 
     33 #include "libelfP.h"
     34 #include "libdwflP.h"
     35 
     36 typedef uint8_t GElf_Byte;
     37 
     38 /* Adjust *VALUE to add the load address of the SHNDX section.
     39    We update the section header in place to cache the result.  */
     40 
     41 Dwfl_Error
     42 internal_function
     43 __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
     44 			  Elf32_Word shndx, GElf_Addr *value)
     45 {
     46   /* No adjustment needed for section zero, it is never loaded.
     47      Handle it first, just in case the ELF file has strange section
     48      zero flags set.  */
     49   if (shndx == 0)
     50     return DWFL_E_NOERROR;
     51 
     52   Elf_Scn *refscn = elf_getscn (elf, shndx);
     53   GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
     54   if (refshdr == NULL)
     55     return DWFL_E_LIBELF;
     56 
     57   if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
     58     {
     59       /* This is a loaded section.  Find its actual
     60 	 address and update the section header.  */
     61 
     62       if (*shstrndx == SHN_UNDEF
     63 	  && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
     64 	return DWFL_E_LIBELF;
     65 
     66       const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
     67       if (unlikely (name == NULL))
     68 	return DWFL_E_LIBELF;
     69 
     70       if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
     71 						    name, shndx, refshdr,
     72 						    &refshdr->sh_addr))
     73 	return CBFAIL;
     74 
     75       if (refshdr->sh_addr == (Dwarf_Addr) -1l)
     76 	/* The callback indicated this section wasn't really loaded but we
     77 	   don't really care.  */
     78 	refshdr->sh_addr = 0;	/* Make no adjustment below.  */
     79 
     80       /* Update the in-core file's section header to show the final
     81 	 load address (or unloadedness).  This serves as a cache,
     82 	 so we won't get here again for the same section.  */
     83       if (likely (refshdr->sh_addr != 0)
     84 	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
     85 	return DWFL_E_LIBELF;
     86     }
     87 
     88   if (refshdr->sh_flags & SHF_ALLOC)
     89     /* Apply the adjustment.  */
     90     *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
     91 
     92   return DWFL_E_NOERROR;
     93 }
     94 
     95 
     96 /* Cache used by relocate_getsym.  */
     97 struct reloc_symtab_cache
     98 {
     99   Elf *symelf;
    100   Elf_Data *symdata;
    101   Elf_Data *symxndxdata;
    102   Elf_Data *symstrdata;
    103   size_t symshstrndx;
    104   size_t strtabndx;
    105 };
    106 #define RELOC_SYMTAB_CACHE(cache)	\
    107   struct reloc_symtab_cache cache =	\
    108     { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
    109 
    110 /* This is just doing dwfl_module_getsym, except that we must always use
    111    the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
    112 static Dwfl_Error
    113 relocate_getsym (Dwfl_Module *mod,
    114 		 Elf *relocated, struct reloc_symtab_cache *cache,
    115 		 int symndx, GElf_Sym *sym, GElf_Word *shndx)
    116 {
    117   if (cache->symdata == NULL)
    118     {
    119       if (mod->symfile == NULL || mod->symfile->elf != relocated)
    120 	{
    121 	  /* We have to look up the symbol table in the file we are
    122 	     relocating, if it has its own.  These reloc sections refer to
    123 	     the symbol table in this file, and a symbol table in the main
    124 	     file might not match.  However, some tools did produce ET_REL
    125 	     .debug files with relocs but no symtab of their own.  */
    126 	  Elf_Scn *scn = NULL;
    127 	  while ((scn = elf_nextscn (relocated, scn)) != NULL)
    128 	    {
    129 	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
    130 	      if (shdr != NULL)
    131 		{
    132 		  /* We need uncompressed data.  */
    133 		  if ((shdr->sh_type == SHT_SYMTAB
    134 		       || shdr->sh_type == SHT_SYMTAB_SHNDX)
    135 		      && (shdr->sh_flags & SHF_COMPRESSED) != 0)
    136 		    if (elf_compress (scn, 0, 0) < 0)
    137 		      return DWFL_E_LIBELF;
    138 
    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 		}
    157 	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
    158 		break;
    159 	    }
    160 	}
    161       if (cache->symdata == NULL)
    162 	{
    163 	  /* We might not have looked for a symbol table file yet,
    164 	     when coming from __libdwfl_relocate_section.  */
    165 	  if (unlikely (mod->symfile == NULL)
    166 	      && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
    167 	    return dwfl_errno ();
    168 
    169 	  /* The symbol table we have already cached is the one from
    170 	     the file being relocated, so it's what we need.  Or else
    171 	     this is an ET_REL .debug file with no .symtab of its own;
    172 	     the symbols refer to the section indices in the main file.  */
    173 	  cache->symelf = mod->symfile->elf;
    174 	  cache->symdata = mod->symdata;
    175 	  cache->symxndxdata = mod->symxndxdata;
    176 	  cache->symstrdata = mod->symstrdata;
    177 	}
    178     }
    179 
    180   if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
    181 				  symndx, sym, shndx) == NULL))
    182     return DWFL_E_LIBELF;
    183 
    184   if (sym->st_shndx != SHN_XINDEX)
    185     *shndx = sym->st_shndx;
    186 
    187   switch (sym->st_shndx)
    188     {
    189     case SHN_ABS:
    190     case SHN_UNDEF:
    191       return DWFL_E_NOERROR;
    192 
    193     case SHN_COMMON:
    194       sym->st_value = 0;	/* Value is size, not helpful. */
    195       return DWFL_E_NOERROR;
    196     }
    197 
    198   return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
    199 				   *shndx, &sym->st_value);
    200 }
    201 
    202 /* Handle an undefined symbol.  We really only support ET_REL for Linux
    203    kernel modules, and offline archives.  The behavior of the Linux module
    204    loader is very simple and easy to mimic.  It only matches magically
    205    exported symbols, and we match any defined symbols.  But we get the same
    206    answer except when the module's symbols are undefined and would prevent
    207    it from being loaded.  */
    208 static Dwfl_Error
    209 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
    210 		GElf_Sym *sym, GElf_Word shndx)
    211 {
    212   /* First we need its name.  */
    213   if (sym->st_name != 0)
    214     {
    215       if (symtab->symstrdata == NULL)
    216 	{
    217 	  /* Cache the strtab for this symtab.  */
    218 	  assert (referer->symfile == NULL
    219 		  || referer->symfile->elf != symtab->symelf);
    220 
    221 	  Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
    222 	  if (scn == NULL)
    223 	    return DWFL_E_LIBELF;
    224 
    225 	  GElf_Shdr shdr_mem;
    226 	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    227 	  if (shdr == NULL)
    228 	    return DWFL_E_LIBELF;
    229 
    230 	  if (symtab->symshstrndx == SHN_UNDEF
    231 	      && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
    232 	    return DWFL_E_LIBELF;
    233 
    234 	  const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
    235 					  shdr->sh_name);
    236 	  if (sname == NULL)
    237 	    return DWFL_E_LIBELF;
    238 
    239 	  /* If the section is already decompressed, that isn't an error.  */
    240 	  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
    241 	    elf_compress_gnu (scn, 0, 0);
    242 
    243 	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    244 	    if (elf_compress (scn, 0, 0) < 0)
    245 	      return DWFL_E_LIBELF;
    246 
    247 	  symtab->symstrdata = elf_getdata (scn, NULL);
    248 	  if (unlikely (symtab->symstrdata == NULL
    249 			|| symtab->symstrdata->d_buf == NULL))
    250 	    return DWFL_E_LIBELF;
    251 	}
    252       if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
    253 	return DWFL_E_BADSTROFF;
    254 
    255       const char *name = symtab->symstrdata->d_buf;
    256       name += sym->st_name;
    257 
    258       for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
    259 	if (m != referer)
    260 	  {
    261 	    /* Get this module's symtab.
    262 	       If we got a fresh error reading the table, report it.
    263 	       If we just have no symbols in this module, no harm done.  */
    264 	    if (m->symdata == NULL
    265 		&& m->symerr == DWFL_E_NOERROR
    266 		&& INTUSE(dwfl_module_getsymtab) (m) < 0
    267 		&& m->symerr != DWFL_E_NO_SYMTAB)
    268 	      return m->symerr;
    269 
    270 	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
    271 	      {
    272 		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
    273 					ndx, sym, &shndx);
    274 		if (unlikely (sym == NULL))
    275 		  return DWFL_E_LIBELF;
    276 		if (sym->st_shndx != SHN_XINDEX)
    277 		  shndx = sym->st_shndx;
    278 
    279 		/* We are looking for a defined global symbol with a name.  */
    280 		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
    281 		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
    282 		    || sym->st_name == 0)
    283 		  continue;
    284 
    285 		/* Get this candidate symbol's name.  */
    286 		if (unlikely (sym->st_name >= m->symstrdata->d_size))
    287 		  return DWFL_E_BADSTROFF;
    288 		const char *n = m->symstrdata->d_buf;
    289 		n += sym->st_name;
    290 
    291 		/* Does the name match?  */
    292 		if (strcmp (name, n))
    293 		  continue;
    294 
    295 		/* We found it!  */
    296 		if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
    297 		  return DWFL_E_NOERROR;
    298 
    299 		if (m->e_type != ET_REL)
    300 		  {
    301 		    sym->st_value = dwfl_adjusted_st_value (m, m->symfile->elf,
    302 							    sym->st_value);
    303 		    return DWFL_E_NOERROR;
    304 		  }
    305 
    306 		/* In an ET_REL file, the symbol table values are relative
    307 		   to the section, not to the module's load base.  */
    308 		size_t symshstrndx = SHN_UNDEF;
    309 		return __libdwfl_relocate_value (m, m->symfile->elf,
    310 						 &symshstrndx,
    311 						 shndx, &sym->st_value);
    312 	      }
    313 	  }
    314     }
    315 
    316   return DWFL_E_RELUNDEF;
    317 }
    318 
    319 /* Apply one relocation.  Returns true for any invalid data.  */
    320 static Dwfl_Error
    321 relocate (Dwfl_Module * const mod,
    322           Elf * const relocated,
    323           struct reloc_symtab_cache * const reloc_symtab,
    324           Elf_Data * const tdata,
    325           const GElf_Ehdr * const ehdr,
    326           GElf_Addr offset,
    327           const GElf_Sxword *addend,
    328           int rtype,
    329           int symndx)
    330 {
    331     /* First see if this is a reloc we can handle.
    332        If we are skipping it, don't bother resolving the symbol.  */
    333 
    334     if (unlikely (rtype == 0))
    335       /* In some odd situations, the linker can leave R_*_NONE relocs
    336 	 behind.  This is probably bogus ld -r behavior, but the only
    337 	 cases it's known to appear in are harmless: DWARF data
    338 	 referring to addresses in a section that has been discarded.
    339 	 So we just pretend it's OK without further relocation.  */
    340       return DWFL_E_NOERROR;
    341 
    342     int addsub = 0;
    343     Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype, &addsub);
    344     if (unlikely (type == ELF_T_NUM))
    345       return DWFL_E_BADRELTYPE;
    346 
    347     /* First, resolve the symbol to an absolute value.  */
    348     GElf_Addr value;
    349 
    350     if (symndx == STN_UNDEF)
    351       /* When strip removes a section symbol referring to a
    352 	 section moved into the debuginfo file, it replaces
    353 	 that symbol index in relocs with STN_UNDEF.  We
    354 	 don't actually need the symbol, because those relocs
    355 	 are always references relative to the nonallocated
    356 	 debugging sections, which start at zero.  */
    357       value = 0;
    358     else
    359       {
    360 	GElf_Sym sym;
    361 	GElf_Word shndx;
    362 	Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
    363 					    symndx, &sym, &shndx);
    364 	if (unlikely (error != DWFL_E_NOERROR))
    365 	  return error;
    366 
    367 	if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
    368 	  {
    369 	    /* Maybe we can figure it out anyway.  */
    370 	    error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
    371 	    if (error != DWFL_E_NOERROR
    372 		&& !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
    373 	      return error;
    374 	  }
    375 
    376 	value = sym.st_value;
    377       }
    378 
    379     /* These are the types we can relocate.  */
    380 #define TYPES		DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);	\
    381     DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);			\
    382     DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
    383     size_t size;
    384     switch (type)
    385       {
    386 #define DO_TYPE(NAME, Name)			\
    387 	case ELF_T_##NAME:			\
    388 	  if (addsub != 0 && addend == NULL)	\
    389 	    /* These do not make sense with SHT_REL.  */ \
    390 	    return DWFL_E_BADRELTYPE;		\
    391 	  size = sizeof (GElf_##Name);		\
    392 	break
    393 	TYPES;
    394 #undef DO_TYPE
    395       default:
    396 	return DWFL_E_BADRELTYPE;
    397       }
    398 
    399     if (offset > tdata->d_size || tdata->d_size - offset < size)
    400       return DWFL_E_BADRELOFF;
    401 
    402 #define DO_TYPE(NAME, Name) GElf_##Name Name;
    403     union { TYPES; } tmpbuf;
    404 #undef DO_TYPE
    405     Elf_Data tmpdata =
    406       {
    407 	.d_type = type,
    408 	.d_buf = &tmpbuf,
    409 	.d_size = size,
    410 	.d_version = EV_CURRENT,
    411       };
    412     Elf_Data rdata =
    413       {
    414 	.d_type = type,
    415 	.d_buf = tdata->d_buf + offset,
    416 	.d_size = size,
    417 	.d_version = EV_CURRENT,
    418       };
    419 
    420     /* XXX check for overflow? */
    421     if (addend)
    422       {
    423 	/* For the addend form, we have the value already.  */
    424 	value += *addend;
    425 	/* For ADD/SUB relocations we need to fetch the section
    426 	   contents.  */
    427 	if (addsub != 0)
    428 	  {
    429 	    Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
    430 					 ehdr->e_ident[EI_DATA]);
    431 	    if (d == NULL)
    432 	      return DWFL_E_LIBELF;
    433 	    assert (d == &tmpdata);
    434 	  }
    435 	switch (type)
    436 	  {
    437 #define DO_TYPE(NAME, Name)			\
    438 	    case ELF_T_##NAME:			\
    439 	      if (addsub != 0)			\
    440 		tmpbuf.Name += value * addsub;	\
    441 	      else				\
    442 		tmpbuf.Name = value;		\
    443 	    break
    444 	    TYPES;
    445 #undef DO_TYPE
    446 	  default:
    447 	    abort ();
    448 	  }
    449       }
    450     else
    451       {
    452 	/* Extract the original value and apply the reloc.  */
    453 	Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
    454 				     ehdr->e_ident[EI_DATA]);
    455 	if (d == NULL)
    456 	  return DWFL_E_LIBELF;
    457 	assert (d == &tmpdata);
    458 	switch (type)
    459 	  {
    460 #define DO_TYPE(NAME, Name)				\
    461 	    case ELF_T_##NAME:				\
    462 	      tmpbuf.Name += (GElf_##Name) value;	\
    463 	    break
    464 	    TYPES;
    465 #undef DO_TYPE
    466 	  default:
    467 	    abort ();
    468 	  }
    469       }
    470 
    471     /* Now convert the relocated datum back to the target
    472        format.  This will write into rdata.d_buf, which
    473        points into the raw section data being relocated.  */
    474     Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
    475 				 ehdr->e_ident[EI_DATA]);
    476     if (s == NULL)
    477       return DWFL_E_LIBELF;
    478     assert (s == &rdata);
    479 
    480     /* We have applied this relocation!  */
    481     return DWFL_E_NOERROR;
    482 }
    483 
    484 static inline void
    485 check_badreltype (bool *first_badreltype,
    486                   Dwfl_Module *mod,
    487                   Dwfl_Error *result)
    488 {
    489   if (*first_badreltype)
    490     {
    491        *first_badreltype = false;
    492        if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
    493           /* This might be because ebl_openbackend failed to find
    494              any libebl_CPU.so library.  Diagnose that clearly.  */
    495           *result = DWFL_E_UNKNOWN_MACHINE;
    496      }
    497 }
    498 
    499 static Dwfl_Error
    500 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
    501 		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
    502 		  Elf_Scn *scn, GElf_Shdr *shdr,
    503 		  Elf_Scn *tscn, bool debugscn, bool partial)
    504 {
    505   /* First, fetch the name of the section these relocations apply to.
    506      Then try to decompress both relocation and target section.  */
    507   GElf_Shdr tshdr_mem;
    508   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
    509   if (tshdr == NULL)
    510     return DWFL_E_LIBELF;
    511 
    512   const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
    513   if (tname == NULL)
    514     return DWFL_E_LIBELF;
    515 
    516   if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
    517     /* This relocation section is not for a debugging section.
    518        Nothing to do here.  */
    519     return DWFL_E_NOERROR;
    520 
    521   if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
    522     elf_compress_gnu (tscn, 0, 0);
    523 
    524   if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
    525     if (elf_compress (tscn, 0, 0) < 0)
    526       return DWFL_E_LIBELF;
    527 
    528   /* Reload Shdr in case section was just decompressed.  */
    529   tshdr = gelf_getshdr (tscn, &tshdr_mem);
    530   if (tshdr == NULL)
    531     return DWFL_E_LIBELF;
    532 
    533   if (unlikely (tshdr->sh_type == SHT_NOBITS)
    534       || unlikely (tshdr->sh_size == 0))
    535     /* No contents to relocate.  */
    536     return DWFL_E_NOERROR;
    537 
    538   const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
    539   if (sname == NULL)
    540     return DWFL_E_LIBELF;
    541 
    542   if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
    543     elf_compress_gnu (scn, 0, 0);
    544 
    545   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    546     if (elf_compress (scn, 0, 0) < 0)
    547       return DWFL_E_LIBELF;
    548 
    549   /* Reload Shdr in case section was just decompressed.  */
    550   GElf_Shdr shdr_mem;
    551   shdr = gelf_getshdr (scn, &shdr_mem);
    552   if (shdr == NULL)
    553     return DWFL_E_LIBELF;
    554 
    555   /* Fetch the section data that needs the relocations applied.  */
    556   Elf_Data *tdata = elf_rawdata (tscn, NULL);
    557   if (tdata == NULL)
    558     return DWFL_E_LIBELF;
    559 
    560   /* If either the section that needs the relocation applied, or the
    561      section that the relocations come from overlap one of the ehdrs,
    562      shdrs or phdrs data then we refuse to do the relocations.  It
    563      isn't illegal for ELF section data to overlap the header data,
    564      but updating the (relocation) data might corrupt the in-memory
    565      libelf headers causing strange corruptions or errors.
    566 
    567      This is only an issue if the ELF is mmapped and the section data
    568      comes from the mmapped region (is not malloced or decompressed).
    569   */
    570   if (relocated->map_address != NULL)
    571     {
    572       size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
    573       if (unlikely (shdr->sh_offset < ehsize
    574 		    || tshdr->sh_offset < ehsize))
    575 	return DWFL_E_BADELF;
    576 
    577       GElf_Off shdrs_start = ehdr->e_shoff;
    578       size_t shnums;
    579       if (elf_getshdrnum (relocated, &shnums) < 0)
    580 	return DWFL_E_LIBELF;
    581       /* Overflows will have been checked by elf_getshdrnum/get|rawdata.  */
    582       size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
    583       GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
    584       if (unlikely (shdrs_start < shdr->sh_offset + shdr->sh_size
    585 		    && shdr->sh_offset < shdrs_end))
    586 	if ((scn->flags & ELF_F_MALLOCED) == 0)
    587 	  return DWFL_E_BADELF;
    588 
    589       if (unlikely (shdrs_start < tshdr->sh_offset + tshdr->sh_size
    590 		    && tshdr->sh_offset < shdrs_end))
    591 	if ((tscn->flags & ELF_F_MALLOCED) == 0)
    592 	  return DWFL_E_BADELF;
    593 
    594       GElf_Off phdrs_start = ehdr->e_phoff;
    595       size_t phnums;
    596       if (elf_getphdrnum (relocated, &phnums) < 0)
    597 	return DWFL_E_LIBELF;
    598       if (phdrs_start != 0 && phnums != 0)
    599 	{
    600 	  /* Overflows will have been checked by elf_getphdrnum/get|rawdata.  */
    601 	  size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
    602 	  GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
    603 	  if (unlikely (phdrs_start < shdr->sh_offset + shdr->sh_size
    604 			&& shdr->sh_offset < phdrs_end))
    605 	    if ((scn->flags & ELF_F_MALLOCED) == 0)
    606 	      return DWFL_E_BADELF;
    607 
    608 	  if (unlikely (phdrs_start < tshdr->sh_offset + tshdr->sh_size
    609 			&& tshdr->sh_offset < phdrs_end))
    610 	    if ((tscn->flags & ELF_F_MALLOCED) == 0)
    611 	      return DWFL_E_BADELF;
    612 	}
    613     }
    614 
    615   /* Fetch the relocation section and apply each reloc in it.  */
    616   Elf_Data *reldata = elf_getdata (scn, NULL);
    617   if (reldata == NULL)
    618     return DWFL_E_LIBELF;
    619 
    620   Dwfl_Error result = DWFL_E_NOERROR;
    621   bool first_badreltype = true;
    622 
    623   size_t sh_entsize
    624     = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
    625 		  1, EV_CURRENT);
    626   size_t nrels = shdr->sh_size / sh_entsize;
    627   size_t complete = 0;
    628   if (shdr->sh_type == SHT_REL)
    629     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    630       {
    631 	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
    632 	if (r == NULL)
    633 	  return DWFL_E_LIBELF;
    634 	result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
    635 			   r->r_offset, NULL,
    636 			   GELF_R_TYPE (r->r_info),
    637 			   GELF_R_SYM (r->r_info));
    638 	check_badreltype (&first_badreltype, mod, &result);
    639 	if (partial)
    640 	  switch (result)
    641 	    {
    642 	    case DWFL_E_NOERROR:
    643 	      /* We applied the relocation.  Elide it.  */
    644 	      memset (&rel_mem, 0, sizeof rel_mem);
    645 	      if (unlikely (gelf_update_rel (reldata, relidx, &rel_mem) == 0))
    646 		return DWFL_E_LIBELF;
    647 	      ++complete;
    648 	      break;
    649 	    case DWFL_E_BADRELTYPE:
    650 	    case DWFL_E_RELUNDEF:
    651 	      /* We couldn't handle this relocation.  Skip it.  */
    652 	      result = DWFL_E_NOERROR;
    653 	      break;
    654 	    default:
    655 	      break;
    656 	    }
    657       }
    658   else
    659     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    660       {
    661 	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
    662 					       &rela_mem);
    663 	if (r == NULL)
    664 	  return DWFL_E_LIBELF;
    665 	result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
    666 			   r->r_offset, &r->r_addend,
    667 			   GELF_R_TYPE (r->r_info),
    668 			   GELF_R_SYM (r->r_info));
    669 	check_badreltype (&first_badreltype, mod, &result);
    670 	if (partial)
    671 	  switch (result)
    672 	    {
    673 	    case DWFL_E_NOERROR:
    674 	      /* We applied the relocation.  Elide it.  */
    675 	      memset (&rela_mem, 0, sizeof rela_mem);
    676 	      if (unlikely (gelf_update_rela (reldata, relidx,
    677 					      &rela_mem) == 0))
    678 		return DWFL_E_LIBELF;
    679 	      ++complete;
    680 	      break;
    681 	    case DWFL_E_BADRELTYPE:
    682 	    case DWFL_E_RELUNDEF:
    683 	      /* We couldn't handle this relocation.  Skip it.  */
    684 	      result = DWFL_E_NOERROR;
    685 	      break;
    686 	    default:
    687 	      break;
    688 	    }
    689       }
    690 
    691   if (likely (result == DWFL_E_NOERROR))
    692     {
    693       if (!partial || complete == nrels)
    694 	/* Mark this relocation section as being empty now that we have
    695 	   done its work.  This affects unstrip -R, so e.g. it emits an
    696 	   empty .rela.debug_info along with a .debug_info that has
    697 	   already been fully relocated.  */
    698 	nrels = 0;
    699       else if (complete != 0)
    700 	{
    701 	  /* We handled some of the relocations but not all.
    702 	     We've zeroed out the ones we processed.
    703 	     Now remove them from the section.  */
    704 
    705 	  size_t next = 0;
    706 	  if (shdr->sh_type == SHT_REL)
    707 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    708 	      {
    709 		GElf_Rel rel_mem;
    710 		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
    711 		if (unlikely (r == NULL))
    712 		  return DWFL_E_LIBELF;
    713 		if (r->r_info != 0 || r->r_offset != 0)
    714 		  {
    715 		    if (next != relidx)
    716 		      if (unlikely (gelf_update_rel (reldata, next, r) == 0))
    717 			return DWFL_E_LIBELF;
    718 		    ++next;
    719 		  }
    720 	      }
    721 	  else
    722 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    723 	      {
    724 		GElf_Rela rela_mem;
    725 		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
    726 		if (unlikely (r == NULL))
    727 		  return DWFL_E_LIBELF;
    728 		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
    729 		  {
    730 		    if (next != relidx)
    731 		      if (unlikely (gelf_update_rela (reldata, next, r) == 0))
    732 			return DWFL_E_LIBELF;
    733 		    ++next;
    734 		  }
    735 	      }
    736 	  nrels = next;
    737 	}
    738 
    739       shdr->sh_size = reldata->d_size = nrels * sh_entsize;
    740       if (unlikely (gelf_update_shdr (scn, shdr) == 0))
    741 	return DWFL_E_LIBELF;
    742     }
    743 
    744   return result;
    745 }
    746 
    747 Dwfl_Error
    748 internal_function
    749 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
    750 {
    751   assert (mod->e_type == ET_REL);
    752 
    753   GElf_Ehdr ehdr_mem;
    754   const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
    755   if (ehdr == NULL)
    756     return DWFL_E_LIBELF;
    757 
    758   size_t d_shstrndx;
    759   if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
    760     return DWFL_E_LIBELF;
    761 
    762   RELOC_SYMTAB_CACHE (reloc_symtab);
    763 
    764   /* Look at each section in the debuginfo file, and process the
    765      relocation sections for debugging sections.  */
    766   Dwfl_Error result = DWFL_E_NOERROR;
    767   Elf_Scn *scn = NULL;
    768   while (result == DWFL_E_NOERROR
    769 	 && (scn = elf_nextscn (debugfile, scn)) != NULL)
    770     {
    771       GElf_Shdr shdr_mem;
    772       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    773       if (unlikely (shdr == NULL))
    774 	return DWFL_E_LIBELF;
    775 
    776       if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
    777 	  && shdr->sh_size != 0)
    778 	{
    779 	  /* It's a relocation section.  */
    780 
    781 	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
    782 	  if (unlikely (tscn == NULL))
    783 	    result = DWFL_E_LIBELF;
    784 	  else
    785 	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
    786 				       &reloc_symtab, scn, shdr, tscn,
    787 				       debug, true /* partial always OK. */);
    788 	}
    789     }
    790 
    791   return result;
    792 }
    793 
    794 Dwfl_Error
    795 internal_function
    796 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
    797 			    Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
    798 {
    799   GElf_Ehdr ehdr_mem;
    800   GElf_Shdr shdr_mem;
    801 
    802   RELOC_SYMTAB_CACHE (reloc_symtab);
    803 
    804   size_t shstrndx;
    805   if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
    806     return DWFL_E_LIBELF;
    807 
    808   Dwfl_Error result = __libdwfl_module_getebl (mod);
    809   if (unlikely (result != DWFL_E_NOERROR))
    810     return result;
    811 
    812   GElf_Ehdr *ehdr = gelf_getehdr (relocated, &ehdr_mem);
    813   if (unlikely (ehdr == NULL))
    814     return DWFL_E_LIBELF;
    815 
    816   GElf_Shdr *shdr = gelf_getshdr (relocscn, &shdr_mem);
    817   if (unlikely (shdr == NULL))
    818     return DWFL_E_LIBELF;
    819 
    820   return relocate_section (mod, relocated, ehdr, shstrndx, &reloc_symtab,
    821 			   relocscn, shdr, tscn, false, partial);
    822 }
    823