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