Home | History | Annotate | Download | only in libdwfl
      1 /* Relocate debug information.
      2    Copyright (C) 2005-2011, 2014 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 #include "libdwflP.h"
     30 
     31 typedef uint8_t GElf_Byte;
     32 
     33 /* Adjust *VALUE to add the load address of the SHNDX section.
     34    We update the section header in place to cache the result.  */
     35 
     36 Dwfl_Error
     37 internal_function
     38 __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
     39 			  Elf32_Word shndx, GElf_Addr *value)
     40 {
     41   /* No adjustment needed for section zero, it is never loaded.
     42      Handle it first, just in case the ELF file has strange section
     43      zero flags set.  */
     44   if (shndx == 0)
     45     return DWFL_E_NOERROR;
     46 
     47   Elf_Scn *refscn = elf_getscn (elf, shndx);
     48   GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
     49   if (refshdr == NULL)
     50     return DWFL_E_LIBELF;
     51 
     52   if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
     53     {
     54       /* This is a loaded section.  Find its actual
     55 	 address and update the section header.  */
     56 
     57       if (*shstrndx == SHN_UNDEF
     58 	  && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
     59 	return DWFL_E_LIBELF;
     60 
     61       const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
     62       if (unlikely (name == NULL))
     63 	return DWFL_E_LIBELF;
     64 
     65       if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
     66 						    name, shndx, refshdr,
     67 						    &refshdr->sh_addr))
     68 	return CBFAIL;
     69 
     70       if (refshdr->sh_addr == (Dwarf_Addr) -1l)
     71 	/* The callback indicated this section wasn't really loaded but we
     72 	   don't really care.  */
     73 	refshdr->sh_addr = 0;	/* Make no adjustment below.  */
     74 
     75       /* Update the in-core file's section header to show the final
     76 	 load address (or unloadedness).  This serves as a cache,
     77 	 so we won't get here again for the same section.  */
     78       if (likely (refshdr->sh_addr != 0)
     79 	  && unlikely (! gelf_update_shdr (refscn, refshdr)))
     80 	return DWFL_E_LIBELF;
     81     }
     82 
     83   if (refshdr->sh_flags & SHF_ALLOC)
     84     /* Apply the adjustment.  */
     85     *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
     86 
     87   return DWFL_E_NOERROR;
     88 }
     89 
     90 
     91 /* Cache used by relocate_getsym.  */
     92 struct reloc_symtab_cache
     93 {
     94   Elf *symelf;
     95   Elf_Data *symdata;
     96   Elf_Data *symxndxdata;
     97   Elf_Data *symstrdata;
     98   size_t symshstrndx;
     99   size_t strtabndx;
    100 };
    101 #define RELOC_SYMTAB_CACHE(cache)	\
    102   struct reloc_symtab_cache cache =	\
    103     { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
    104 
    105 /* This is just doing dwfl_module_getsym, except that we must always use
    106    the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
    107 static Dwfl_Error
    108 relocate_getsym (Dwfl_Module *mod,
    109 		 Elf *relocated, struct reloc_symtab_cache *cache,
    110 		 int symndx, GElf_Sym *sym, GElf_Word *shndx)
    111 {
    112   if (cache->symdata == NULL)
    113     {
    114       if (mod->symfile == NULL || mod->symfile->elf != relocated)
    115 	{
    116 	  /* We have to look up the symbol table in the file we are
    117 	     relocating, if it has its own.  These reloc sections refer to
    118 	     the symbol table in this file, and a symbol table in the main
    119 	     file might not match.  However, some tools did produce ET_REL
    120 	     .debug files with relocs but no symtab of their own.  */
    121 	  Elf_Scn *scn = NULL;
    122 	  while ((scn = elf_nextscn (relocated, scn)) != NULL)
    123 	    {
    124 	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
    125 	      if (shdr != NULL)
    126 		{
    127 		  /* We need uncompressed data.  */
    128 		  if ((shdr->sh_type == SHT_SYMTAB
    129 		       || shdr->sh_type == SHT_SYMTAB_SHNDX)
    130 		      && (shdr->sh_flags & SHF_COMPRESSED) != 0)
    131 		    if (elf_compress (scn, 0, 0) < 0)
    132 		      return DWFL_E_LIBELF;
    133 
    134 		  switch (shdr->sh_type)
    135 		    {
    136 		    default:
    137 		      continue;
    138 		    case SHT_SYMTAB:
    139 		      cache->symelf = relocated;
    140 		      cache->symdata = elf_getdata (scn, NULL);
    141 		      cache->strtabndx = shdr->sh_link;
    142 		      if (unlikely (cache->symdata == NULL))
    143 			return DWFL_E_LIBELF;
    144 		      break;
    145 		    case SHT_SYMTAB_SHNDX:
    146 		      cache->symxndxdata = elf_getdata (scn, NULL);
    147 		      if (unlikely (cache->symxndxdata == NULL))
    148 			return DWFL_E_LIBELF;
    149 		      break;
    150 		    }
    151 		}
    152 	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
    153 		break;
    154 	    }
    155 	}
    156       if (cache->symdata == NULL)
    157 	{
    158 	  /* We might not have looked for a symbol table file yet,
    159 	     when coming from __libdwfl_relocate_section.  */
    160 	  if (unlikely (mod->symfile == NULL)
    161 	      && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
    162 	    return dwfl_errno ();
    163 
    164 	  /* The symbol table we have already cached is the one from
    165 	     the file being relocated, so it's what we need.  Or else
    166 	     this is an ET_REL .debug file with no .symtab of its own;
    167 	     the symbols refer to the section indices in the main file.  */
    168 	  cache->symelf = mod->symfile->elf;
    169 	  cache->symdata = mod->symdata;
    170 	  cache->symxndxdata = mod->symxndxdata;
    171 	  cache->symstrdata = mod->symstrdata;
    172 	}
    173     }
    174 
    175   if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
    176 				  symndx, sym, shndx) == NULL))
    177     return DWFL_E_LIBELF;
    178 
    179   if (sym->st_shndx != SHN_XINDEX)
    180     *shndx = sym->st_shndx;
    181 
    182   switch (sym->st_shndx)
    183     {
    184     case SHN_ABS:
    185     case SHN_UNDEF:
    186       return DWFL_E_NOERROR;
    187 
    188     case SHN_COMMON:
    189       sym->st_value = 0;	/* Value is size, not helpful. */
    190       return DWFL_E_NOERROR;
    191     }
    192 
    193   return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
    194 				   *shndx, &sym->st_value);
    195 }
    196 
    197 /* Handle an undefined symbol.  We really only support ET_REL for Linux
    198    kernel modules, and offline archives.  The behavior of the Linux module
    199    loader is very simple and easy to mimic.  It only matches magically
    200    exported symbols, and we match any defined symbols.  But we get the same
    201    answer except when the module's symbols are undefined and would prevent
    202    it from being loaded.  */
    203 static Dwfl_Error
    204 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
    205 		GElf_Sym *sym, GElf_Word shndx)
    206 {
    207   /* First we need its name.  */
    208   if (sym->st_name != 0)
    209     {
    210       if (symtab->symstrdata == NULL)
    211 	{
    212 	  /* Cache the strtab for this symtab.  */
    213 	  assert (referer->symfile == NULL
    214 		  || referer->symfile->elf != symtab->symelf);
    215 
    216 	  Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
    217 	  if (scn == NULL)
    218 	    return DWFL_E_LIBELF;
    219 
    220 	  GElf_Shdr shdr_mem;
    221 	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    222 	  if (shdr == NULL)
    223 	    return DWFL_E_LIBELF;
    224 
    225 	  if (symtab->symshstrndx == SHN_UNDEF
    226 	      && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
    227 	    return DWFL_E_LIBELF;
    228 
    229 	  const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
    230 					  shdr->sh_name);
    231 	  if (sname == NULL)
    232 	    return DWFL_E_LIBELF;
    233 
    234 	  /* If the section is already decompressed, that isn't an error.  */
    235 	  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
    236 	    elf_compress_gnu (scn, 0, 0);
    237 
    238 	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    239 	    if (elf_compress (scn, 0, 0) < 0)
    240 	      return DWFL_E_LIBELF;
    241 
    242 	  symtab->symstrdata = elf_getdata (scn, NULL);
    243 	  if (unlikely (symtab->symstrdata == NULL
    244 			|| symtab->symstrdata->d_buf == NULL))
    245 	    return DWFL_E_LIBELF;
    246 	}
    247       if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
    248 	return DWFL_E_BADSTROFF;
    249 
    250       const char *name = symtab->symstrdata->d_buf;
    251       name += sym->st_name;
    252 
    253       for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
    254 	if (m != referer)
    255 	  {
    256 	    /* Get this module's symtab.
    257 	       If we got a fresh error reading the table, report it.
    258 	       If we just have no symbols in this module, no harm done.  */
    259 	    if (m->symdata == NULL
    260 		&& m->symerr == DWFL_E_NOERROR
    261 		&& INTUSE(dwfl_module_getsymtab) (m) < 0
    262 		&& m->symerr != DWFL_E_NO_SYMTAB)
    263 	      return m->symerr;
    264 
    265 	    for (size_t ndx = 1; ndx < m->syments; ++ndx)
    266 	      {
    267 		sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
    268 					ndx, sym, &shndx);
    269 		if (unlikely (sym == NULL))
    270 		  return DWFL_E_LIBELF;
    271 		if (sym->st_shndx != SHN_XINDEX)
    272 		  shndx = sym->st_shndx;
    273 
    274 		/* We are looking for a defined global symbol with a name.  */
    275 		if (shndx == SHN_UNDEF || shndx == SHN_COMMON
    276 		    || GELF_ST_BIND (sym->st_info) == STB_LOCAL
    277 		    || sym->st_name == 0)
    278 		  continue;
    279 
    280 		/* Get this candidate symbol's name.  */
    281 		if (unlikely (sym->st_name >= m->symstrdata->d_size))
    282 		  return DWFL_E_BADSTROFF;
    283 		const char *n = m->symstrdata->d_buf;
    284 		n += sym->st_name;
    285 
    286 		/* Does the name match?  */
    287 		if (strcmp (name, n))
    288 		  continue;
    289 
    290 		/* We found it!  */
    291 		if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
    292 		  return DWFL_E_NOERROR;
    293 
    294 		if (m->e_type != ET_REL)
    295 		  {
    296 		    sym->st_value = dwfl_adjusted_st_value (m, m->symfile->elf,
    297 							    sym->st_value);
    298 		    return DWFL_E_NOERROR;
    299 		  }
    300 
    301 		/* In an ET_REL file, the symbol table values are relative
    302 		   to the section, not to the module's load base.  */
    303 		size_t symshstrndx = SHN_UNDEF;
    304 		return __libdwfl_relocate_value (m, m->symfile->elf,
    305 						 &symshstrndx,
    306 						 shndx, &sym->st_value);
    307 	      }
    308 	  }
    309     }
    310 
    311   return DWFL_E_RELUNDEF;
    312 }
    313 
    314 /* Apply one relocation.  Returns true for any invalid data.  */
    315 static Dwfl_Error
    316 relocate (Dwfl_Module * const mod,
    317           Elf * const relocated,
    318           struct reloc_symtab_cache * const reloc_symtab,
    319           Elf_Data * const tdata,
    320           const GElf_Ehdr * const ehdr,
    321           GElf_Addr offset,
    322           const GElf_Sxword *addend,
    323           int rtype,
    324           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 > tdata->d_size || tdata->d_size - offset < 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 static inline void
    463 check_badreltype (bool *first_badreltype,
    464                   Dwfl_Module *mod,
    465                   Dwfl_Error *result)
    466 {
    467   if (*first_badreltype)
    468     {
    469        *first_badreltype = false;
    470        if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
    471           /* This might be because ebl_openbackend failed to find
    472              any libebl_CPU.so library.  Diagnose that clearly.  */
    473           *result = DWFL_E_UNKNOWN_MACHINE;
    474      }
    475 }
    476 
    477 static Dwfl_Error
    478 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
    479 		  size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
    480 		  Elf_Scn *scn, GElf_Shdr *shdr,
    481 		  Elf_Scn *tscn, bool debugscn, bool partial)
    482 {
    483   /* First, fetch the name of the section these relocations apply to.
    484      Then try to decompress both relocation and target section.  */
    485   GElf_Shdr tshdr_mem;
    486   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
    487   if (tshdr == NULL)
    488     return DWFL_E_LIBELF;
    489 
    490   const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
    491   if (tname == NULL)
    492     return DWFL_E_LIBELF;
    493 
    494   if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
    495     /* This relocation section is not for a debugging section.
    496        Nothing to do here.  */
    497     return DWFL_E_NOERROR;
    498 
    499   if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
    500     elf_compress_gnu (tscn, 0, 0);
    501 
    502   if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
    503     if (elf_compress (tscn, 0, 0) < 0)
    504       return DWFL_E_LIBELF;
    505 
    506   /* Reload Shdr in case section was just decompressed.  */
    507   tshdr = gelf_getshdr (tscn, &tshdr_mem);
    508   if (tshdr == NULL)
    509     return DWFL_E_LIBELF;
    510 
    511   if (unlikely (tshdr->sh_type == SHT_NOBITS)
    512       || unlikely (tshdr->sh_size == 0))
    513     /* No contents to relocate.  */
    514     return DWFL_E_NOERROR;
    515 
    516   const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
    517   if (sname == NULL)
    518     return DWFL_E_LIBELF;
    519 
    520   if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
    521     elf_compress_gnu (scn, 0, 0);
    522 
    523   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    524     if (elf_compress (scn, 0, 0) < 0)
    525       return DWFL_E_LIBELF;
    526 
    527   /* Reload Shdr in case section was just decompressed.  */
    528   GElf_Shdr shdr_mem;
    529   shdr = gelf_getshdr (scn, &shdr_mem);
    530   if (shdr == NULL)
    531     return DWFL_E_LIBELF;
    532 
    533   /* Fetch the section data that needs the relocations applied.  */
    534   Elf_Data *tdata = elf_rawdata (tscn, NULL);
    535   if (tdata == NULL)
    536     return DWFL_E_LIBELF;
    537 
    538   /* If either the section that needs the relocation applied, or the
    539      section that the relocations come from overlap one of the ehdrs,
    540      shdrs or phdrs data then we refuse to do the relocations.  It
    541      isn't illegal for ELF section data to overlap the header data,
    542      but updating the (relocation) data might corrupt the in-memory
    543      libelf headers causing strange corruptions or errors.  */
    544   size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
    545   if (unlikely (shdr->sh_offset < ehsize
    546 		|| tshdr->sh_offset < ehsize))
    547     return DWFL_E_BADELF;
    548 
    549   GElf_Off shdrs_start = ehdr->e_shoff;
    550   size_t shnums;
    551   if (elf_getshdrnum (relocated, &shnums) < 0)
    552     return DWFL_E_LIBELF;
    553   /* Overflows will have been checked by elf_getshdrnum/get|rawdata.  */
    554   size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
    555   GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
    556   if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size
    557 		 && shdr->sh_offset < shdrs_end)
    558 		|| (shdrs_start < tshdr->sh_offset + tshdr->sh_size
    559 		    && tshdr->sh_offset < shdrs_end)))
    560     return DWFL_E_BADELF;
    561 
    562   GElf_Off phdrs_start = ehdr->e_phoff;
    563   size_t phnums;
    564   if (elf_getphdrnum (relocated, &phnums) < 0)
    565     return DWFL_E_LIBELF;
    566   if (phdrs_start != 0 && phnums != 0)
    567     {
    568       /* Overflows will have been checked by elf_getphdrnum/get|rawdata.  */
    569       size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
    570       GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
    571       if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size
    572 		     && shdr->sh_offset < phdrs_end)
    573 		    || (phdrs_start < tshdr->sh_offset + tshdr->sh_size
    574 			&& tshdr->sh_offset < phdrs_end)))
    575 	return DWFL_E_BADELF;
    576     }
    577 
    578   /* Fetch the relocation section and apply each reloc in it.  */
    579   Elf_Data *reldata = elf_getdata (scn, NULL);
    580   if (reldata == NULL)
    581     return DWFL_E_LIBELF;
    582 
    583   Dwfl_Error result = DWFL_E_NOERROR;
    584   bool first_badreltype = true;
    585 
    586   size_t sh_entsize
    587     = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
    588 		  1, EV_CURRENT);
    589   size_t nrels = shdr->sh_size / sh_entsize;
    590   size_t complete = 0;
    591   if (shdr->sh_type == SHT_REL)
    592     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    593       {
    594 	GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
    595 	if (r == NULL)
    596 	  return DWFL_E_LIBELF;
    597 	result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
    598 			   r->r_offset, NULL,
    599 			   GELF_R_TYPE (r->r_info),
    600 			   GELF_R_SYM (r->r_info));
    601 	check_badreltype (&first_badreltype, mod, &result);
    602 	if (partial)
    603 	  switch (result)
    604 	    {
    605 	    case DWFL_E_NOERROR:
    606 	      /* We applied the relocation.  Elide it.  */
    607 	      memset (&rel_mem, 0, sizeof rel_mem);
    608 	      gelf_update_rel (reldata, relidx, &rel_mem);
    609 	      ++complete;
    610 	      break;
    611 	    case DWFL_E_BADRELTYPE:
    612 	    case DWFL_E_RELUNDEF:
    613 	      /* We couldn't handle this relocation.  Skip it.  */
    614 	      result = DWFL_E_NOERROR;
    615 	      break;
    616 	    default:
    617 	      break;
    618 	    }
    619       }
    620   else
    621     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
    622       {
    623 	GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
    624 					       &rela_mem);
    625 	if (r == NULL)
    626 	  return DWFL_E_LIBELF;
    627 	result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
    628 			   r->r_offset, &r->r_addend,
    629 			   GELF_R_TYPE (r->r_info),
    630 			   GELF_R_SYM (r->r_info));
    631 	check_badreltype (&first_badreltype, mod, &result);
    632 	if (partial)
    633 	  switch (result)
    634 	    {
    635 	    case DWFL_E_NOERROR:
    636 	      /* We applied the relocation.  Elide it.  */
    637 	      memset (&rela_mem, 0, sizeof rela_mem);
    638 	      gelf_update_rela (reldata, relidx, &rela_mem);
    639 	      ++complete;
    640 	      break;
    641 	    case DWFL_E_BADRELTYPE:
    642 	    case DWFL_E_RELUNDEF:
    643 	      /* We couldn't handle this relocation.  Skip it.  */
    644 	      result = DWFL_E_NOERROR;
    645 	      break;
    646 	    default:
    647 	      break;
    648 	    }
    649       }
    650 
    651   if (likely (result == DWFL_E_NOERROR))
    652     {
    653       if (!partial || complete == nrels)
    654 	/* Mark this relocation section as being empty now that we have
    655 	   done its work.  This affects unstrip -R, so e.g. it emits an
    656 	   empty .rela.debug_info along with a .debug_info that has
    657 	   already been fully relocated.  */
    658 	nrels = 0;
    659       else if (complete != 0)
    660 	{
    661 	  /* We handled some of the relocations but not all.
    662 	     We've zeroed out the ones we processed.
    663 	     Now remove them from the section.  */
    664 
    665 	  size_t next = 0;
    666 	  if (shdr->sh_type == SHT_REL)
    667 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    668 	      {
    669 		GElf_Rel rel_mem;
    670 		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
    671 		if (r->r_info != 0 || r->r_offset != 0)
    672 		  {
    673 		    if (next != relidx)
    674 		      gelf_update_rel (reldata, next, r);
    675 		    ++next;
    676 		  }
    677 	      }
    678 	  else
    679 	    for (size_t relidx = 0; relidx < nrels; ++relidx)
    680 	      {
    681 		GElf_Rela rela_mem;
    682 		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
    683 		if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
    684 		  {
    685 		    if (next != relidx)
    686 		      gelf_update_rela (reldata, next, r);
    687 		    ++next;
    688 		  }
    689 	      }
    690 	  nrels = next;
    691 	}
    692 
    693       shdr->sh_size = reldata->d_size = nrels * sh_entsize;
    694       gelf_update_shdr (scn, shdr);
    695     }
    696 
    697   return result;
    698 }
    699 
    700 Dwfl_Error
    701 internal_function
    702 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
    703 {
    704   assert (mod->e_type == ET_REL);
    705 
    706   GElf_Ehdr ehdr_mem;
    707   const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
    708   if (ehdr == NULL)
    709     return DWFL_E_LIBELF;
    710 
    711   size_t d_shstrndx;
    712   if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
    713     return DWFL_E_LIBELF;
    714 
    715   RELOC_SYMTAB_CACHE (reloc_symtab);
    716 
    717   /* Look at each section in the debuginfo file, and process the
    718      relocation sections for debugging sections.  */
    719   Dwfl_Error result = DWFL_E_NOERROR;
    720   Elf_Scn *scn = NULL;
    721   while (result == DWFL_E_NOERROR
    722 	 && (scn = elf_nextscn (debugfile, scn)) != NULL)
    723     {
    724       GElf_Shdr shdr_mem;
    725       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    726 
    727       if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
    728 	  && shdr->sh_size != 0)
    729 	{
    730 	  /* It's a relocation section.  */
    731 
    732 	  Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
    733 	  if (unlikely (tscn == NULL))
    734 	    result = DWFL_E_LIBELF;
    735 	  else
    736 	    result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
    737 				       &reloc_symtab, scn, shdr, tscn,
    738 				       debug, !debug);
    739 	}
    740     }
    741 
    742   return result;
    743 }
    744 
    745 Dwfl_Error
    746 internal_function
    747 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
    748 			    Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
    749 {
    750   GElf_Ehdr ehdr_mem;
    751   GElf_Shdr shdr_mem;
    752 
    753   RELOC_SYMTAB_CACHE (reloc_symtab);
    754 
    755   size_t shstrndx;
    756   if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
    757     return DWFL_E_LIBELF;
    758 
    759   return (__libdwfl_module_getebl (mod)
    760 	  ?: relocate_section (mod, relocated,
    761 			       gelf_getehdr (relocated, &ehdr_mem), shstrndx,
    762 			       &reloc_symtab,
    763 			       relocscn, gelf_getshdr (relocscn, &shdr_mem),
    764 			       tscn, false, partial));
    765 }
    766