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
31typedef 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
36Dwfl_Error
37internal_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.  */
92struct 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.  */
107static Dwfl_Error
108relocate_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.  */
203static Dwfl_Error
204resolve_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.  */
315static Dwfl_Error
316relocate (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
462static inline void
463check_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
477static Dwfl_Error
478relocate_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
700Dwfl_Error
701internal_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
745Dwfl_Error
746internal_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