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
__libdwfl_relocate_value(Dwfl_Module * mod,Elf * elf,size_t * shstrndx,Elf32_Word shndx,GElf_Addr * value)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
relocate_getsym(Dwfl_Module * mod,Elf * relocated,struct reloc_symtab_cache * cache,int symndx,GElf_Sym * sym,GElf_Word * shndx)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
resolve_symbol(Dwfl_Module * referer,struct reloc_symtab_cache * symtab,GElf_Sym * sym,GElf_Word shndx)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
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)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
check_badreltype(bool * first_badreltype,Dwfl_Module * mod,Dwfl_Error * result)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
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)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
__libdwfl_relocate(Dwfl_Module * mod,Elf * debugfile,bool debug)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
__libdwfl_relocate_section(Dwfl_Module * mod,Elf * relocated,Elf_Scn * relocscn,Elf_Scn * tscn,bool partial)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