• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
__libdwfl_relocate_value(Dwfl_Module * mod,Elf * elf,size_t * shstrndx,Elf32_Word shndx,GElf_Addr * value)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
relocate_getsym(Dwfl_Module * mod,Elf * relocated,struct reloc_symtab_cache * cache,int symndx,GElf_Sym * sym,GElf_Word * shndx)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
resolve_symbol(Dwfl_Module * referer,struct reloc_symtab_cache * symtab,GElf_Sym * sym,GElf_Word shndx)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
relocate(Dwfl_Module * const mod,Elf * const relocated,struct reloc_symtab_cache * const reloc_symtab,Elf_Data * const tdata,const GElf_Ehdr * const ehdr,GElf_Addr offset,const GElf_Sxword * addend,int rtype,int symndx)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
check_badreltype(bool * first_badreltype,Dwfl_Module * mod,Dwfl_Error * result)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
relocate_section(Dwfl_Module * mod,Elf * relocated,const GElf_Ehdr * ehdr,size_t shstrndx,struct reloc_symtab_cache * reloc_symtab,Elf_Scn * scn,GElf_Shdr * shdr,Elf_Scn * tscn,bool debugscn,bool partial)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
__libdwfl_relocate(Dwfl_Module * mod,Elf * debugfile,bool debug)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
__libdwfl_relocate_section(Dwfl_Module * mod,Elf * relocated,Elf_Scn * relocscn,Elf_Scn * tscn,bool partial)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