Line data Source code
1 : /* Relocate debug information.
2 : Copyright (C) 2005-2011, 2014, 2016 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 "libdwflP.h"
34 :
35 : typedef uint8_t GElf_Byte;
36 :
37 : /* Adjust *VALUE to add the load address of the SHNDX section.
38 : We update the section header in place to cache the result. */
39 :
40 : Dwfl_Error
41 : internal_function
42 6638254 : __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
43 : Elf32_Word shndx, GElf_Addr *value)
44 : {
45 : /* No adjustment needed for section zero, it is never loaded.
46 : Handle it first, just in case the ELF file has strange section
47 : zero flags set. */
48 3598804 : if (shndx == 0)
49 : return DWFL_E_NOERROR;
50 :
51 3598804 : Elf_Scn *refscn = elf_getscn (elf, shndx);
52 3598804 : GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
53 3598804 : if (refshdr == NULL)
54 : return DWFL_E_LIBELF;
55 :
56 3598804 : if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
57 : {
58 : /* This is a loaded section. Find its actual
59 : address and update the section header. */
60 :
61 403367 : if (*shstrndx == SHN_UNDEF
62 331629 : && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
63 : return DWFL_E_LIBELF;
64 :
65 403367 : const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
66 403367 : if (unlikely (name == NULL))
67 : return DWFL_E_LIBELF;
68 :
69 806734 : if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
70 : name, shndx, refshdr,
71 403367 : &refshdr->sh_addr))
72 0 : return CBFAIL;
73 :
74 403367 : if (refshdr->sh_addr == (Dwarf_Addr) -1l)
75 : /* The callback indicated this section wasn't really loaded but we
76 : don't really care. */
77 0 : refshdr->sh_addr = 0; /* Make no adjustment below. */
78 :
79 : /* Update the in-core file's section header to show the final
80 : load address (or unloadedness). This serves as a cache,
81 : so we won't get here again for the same section. */
82 403367 : if (likely (refshdr->sh_addr != 0)
83 4 : && unlikely (! gelf_update_shdr (refscn, refshdr)))
84 : return DWFL_E_LIBELF;
85 : }
86 :
87 3598804 : if (refshdr->sh_flags & SHF_ALLOC)
88 : /* Apply the adjustment. */
89 9118350 : *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
90 :
91 : return DWFL_E_NOERROR;
92 : }
93 :
94 :
95 : /* Cache used by relocate_getsym. */
96 : struct reloc_symtab_cache
97 : {
98 : Elf *symelf;
99 : Elf_Data *symdata;
100 : Elf_Data *symxndxdata;
101 : Elf_Data *symstrdata;
102 : size_t symshstrndx;
103 : size_t strtabndx;
104 : };
105 : #define RELOC_SYMTAB_CACHE(cache) \
106 : struct reloc_symtab_cache cache = \
107 : { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
108 :
109 : /* This is just doing dwfl_module_getsym, except that we must always use
110 : the symbol table in RELOCATED itself when it has one, not MOD->symfile. */
111 : static Dwfl_Error
112 138569 : relocate_getsym (Dwfl_Module *mod,
113 : Elf *relocated, struct reloc_symtab_cache *cache,
114 : int symndx, GElf_Sym *sym, GElf_Word *shndx)
115 : {
116 138569 : if (cache->symdata == NULL)
117 : {
118 92 : if (mod->symfile == NULL || mod->symfile->elf != relocated)
119 : {
120 : /* We have to look up the symbol table in the file we are
121 : relocating, if it has its own. These reloc sections refer to
122 : the symbol table in this file, and a symbol table in the main
123 : file might not match. However, some tools did produce ET_REL
124 : .debug files with relocs but no symtab of their own. */
125 : Elf_Scn *scn = NULL;
126 1397 : while ((scn = elf_nextscn (relocated, scn)) != NULL)
127 : {
128 1338 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
129 1338 : if (shdr != NULL)
130 : {
131 : /* We need uncompressed data. */
132 2676 : if ((shdr->sh_type == SHT_SYMTAB
133 1338 : || shdr->sh_type == SHT_SYMTAB_SHNDX)
134 59 : && (shdr->sh_flags & SHF_COMPRESSED) != 0)
135 0 : if (elf_compress (scn, 0, 0) < 0)
136 0 : return DWFL_E_LIBELF;
137 :
138 1338 : switch (shdr->sh_type)
139 : {
140 : default:
141 1279 : continue;
142 : case SHT_SYMTAB:
143 59 : cache->symelf = relocated;
144 59 : cache->symdata = elf_getdata (scn, NULL);
145 59 : cache->strtabndx = shdr->sh_link;
146 59 : if (unlikely (cache->symdata == NULL))
147 : return DWFL_E_LIBELF;
148 : break;
149 : case SHT_SYMTAB_SHNDX:
150 0 : cache->symxndxdata = elf_getdata (scn, NULL);
151 0 : if (unlikely (cache->symxndxdata == NULL))
152 : return DWFL_E_LIBELF;
153 : break;
154 : }
155 : }
156 59 : if (cache->symdata != NULL && cache->symxndxdata != NULL)
157 : break;
158 : }
159 : }
160 92 : if (cache->symdata == NULL)
161 : {
162 : /* We might not have looked for a symbol table file yet,
163 : when coming from __libdwfl_relocate_section. */
164 33 : if (unlikely (mod->symfile == NULL)
165 0 : && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
166 0 : return dwfl_errno ();
167 :
168 : /* The symbol table we have already cached is the one from
169 : the file being relocated, so it's what we need. Or else
170 : this is an ET_REL .debug file with no .symtab of its own;
171 : the symbols refer to the section indices in the main file. */
172 33 : cache->symelf = mod->symfile->elf;
173 33 : cache->symdata = mod->symdata;
174 33 : cache->symxndxdata = mod->symxndxdata;
175 33 : cache->symstrdata = mod->symstrdata;
176 : }
177 : }
178 :
179 138569 : if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
180 : symndx, sym, shndx) == NULL))
181 : return DWFL_E_LIBELF;
182 :
183 138569 : if (sym->st_shndx != SHN_XINDEX)
184 138569 : *shndx = sym->st_shndx;
185 :
186 138569 : switch (sym->st_shndx)
187 : {
188 : case SHN_ABS:
189 : case SHN_UNDEF:
190 : return DWFL_E_NOERROR;
191 :
192 : case SHN_COMMON:
193 78 : sym->st_value = 0; /* Value is size, not helpful. */
194 78 : return DWFL_E_NOERROR;
195 : }
196 :
197 138450 : return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
198 138450 : *shndx, &sym->st_value);
199 : }
200 :
201 : /* Handle an undefined symbol. We really only support ET_REL for Linux
202 : kernel modules, and offline archives. The behavior of the Linux module
203 : loader is very simple and easy to mimic. It only matches magically
204 : exported symbols, and we match any defined symbols. But we get the same
205 : answer except when the module's symbols are undefined and would prevent
206 : it from being loaded. */
207 : static Dwfl_Error
208 119 : resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
209 : GElf_Sym *sym, GElf_Word shndx)
210 : {
211 : /* First we need its name. */
212 119 : if (sym->st_name != 0)
213 : {
214 119 : if (symtab->symstrdata == NULL)
215 : {
216 : /* Cache the strtab for this symtab. */
217 14 : assert (referer->symfile == NULL
218 : || referer->symfile->elf != symtab->symelf);
219 :
220 14 : Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
221 14 : if (scn == NULL)
222 0 : return DWFL_E_LIBELF;
223 :
224 : GElf_Shdr shdr_mem;
225 14 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
226 14 : if (shdr == NULL)
227 : return DWFL_E_LIBELF;
228 :
229 14 : if (symtab->symshstrndx == SHN_UNDEF
230 14 : && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
231 : return DWFL_E_LIBELF;
232 :
233 14 : const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
234 14 : shdr->sh_name);
235 14 : if (sname == NULL)
236 : return DWFL_E_LIBELF;
237 :
238 : /* If the section is already decompressed, that isn't an error. */
239 14 : if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
240 0 : elf_compress_gnu (scn, 0, 0);
241 :
242 14 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
243 0 : if (elf_compress (scn, 0, 0) < 0)
244 : return DWFL_E_LIBELF;
245 :
246 14 : symtab->symstrdata = elf_getdata (scn, NULL);
247 14 : if (unlikely (symtab->symstrdata == NULL
248 : || symtab->symstrdata->d_buf == NULL))
249 : return DWFL_E_LIBELF;
250 : }
251 119 : if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
252 : return DWFL_E_BADSTROFF;
253 :
254 119 : const char *name = symtab->symstrdata->d_buf;
255 119 : name += sym->st_name;
256 :
257 238 : for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
258 119 : if (m != referer)
259 : {
260 : /* Get this module's symtab.
261 : If we got a fresh error reading the table, report it.
262 : If we just have no symbols in this module, no harm done. */
263 0 : if (m->symdata == NULL
264 0 : && m->symerr == DWFL_E_NOERROR
265 0 : && INTUSE(dwfl_module_getsymtab) (m) < 0
266 0 : && m->symerr != DWFL_E_NO_SYMTAB)
267 : return m->symerr;
268 :
269 0 : for (size_t ndx = 1; ndx < m->syments; ++ndx)
270 : {
271 0 : sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
272 : ndx, sym, &shndx);
273 0 : if (unlikely (sym == NULL))
274 0 : return DWFL_E_LIBELF;
275 0 : if (sym->st_shndx != SHN_XINDEX)
276 0 : shndx = sym->st_shndx;
277 :
278 : /* We are looking for a defined global symbol with a name. */
279 0 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON
280 0 : || GELF_ST_BIND (sym->st_info) == STB_LOCAL
281 0 : || sym->st_name == 0)
282 0 : continue;
283 :
284 : /* Get this candidate symbol's name. */
285 0 : if (unlikely (sym->st_name >= m->symstrdata->d_size))
286 : return DWFL_E_BADSTROFF;
287 0 : const char *n = m->symstrdata->d_buf;
288 0 : n += sym->st_name;
289 :
290 : /* Does the name match? */
291 0 : if (strcmp (name, n))
292 0 : continue;
293 :
294 : /* We found it! */
295 0 : if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
296 : return DWFL_E_NOERROR;
297 :
298 0 : if (m->e_type != ET_REL)
299 : {
300 0 : sym->st_value = dwfl_adjusted_st_value (m, m->symfile->elf,
301 : sym->st_value);
302 0 : return DWFL_E_NOERROR;
303 : }
304 :
305 : /* In an ET_REL file, the symbol table values are relative
306 : to the section, not to the module's load base. */
307 0 : size_t symshstrndx = SHN_UNDEF;
308 0 : return __libdwfl_relocate_value (m, m->symfile->elf,
309 : &symshstrndx,
310 0 : shndx, &sym->st_value);
311 : }
312 : }
313 : }
314 :
315 : return DWFL_E_RELUNDEF;
316 : }
317 :
318 : /* Apply one relocation. Returns true for any invalid data. */
319 : static Dwfl_Error
320 153194 : relocate (Dwfl_Module * const mod,
321 : Elf * const relocated,
322 : struct reloc_symtab_cache * const reloc_symtab,
323 : Elf_Data * const tdata,
324 : const GElf_Ehdr * const ehdr,
325 : GElf_Addr offset,
326 : const GElf_Sxword *addend,
327 : int rtype,
328 : int symndx)
329 : {
330 : /* First see if this is a reloc we can handle.
331 : If we are skipping it, don't bother resolving the symbol. */
332 :
333 153194 : if (unlikely (rtype == 0))
334 : /* In some odd situations, the linker can leave R_*_NONE relocs
335 : behind. This is probably bogus ld -r behavior, but the only
336 : cases it's known to appear in are harmless: DWARF data
337 : referring to addresses in a section that has been discarded.
338 : So we just pretend it's OK without further relocation. */
339 : return DWFL_E_NOERROR;
340 :
341 153194 : Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
342 153194 : if (unlikely (type == ELF_T_NUM))
343 : return DWFL_E_BADRELTYPE;
344 :
345 : /* First, resolve the symbol to an absolute value. */
346 : GElf_Addr value;
347 :
348 138573 : if (symndx == STN_UNDEF)
349 : /* When strip removes a section symbol referring to a
350 : section moved into the debuginfo file, it replaces
351 : that symbol index in relocs with STN_UNDEF. We
352 : don't actually need the symbol, because those relocs
353 : are always references relative to the nonallocated
354 : debugging sections, which start at zero. */
355 : value = 0;
356 : else
357 : {
358 : GElf_Sym sym;
359 : GElf_Word shndx;
360 138569 : Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
361 : symndx, &sym, &shndx);
362 138569 : if (unlikely (error != DWFL_E_NOERROR))
363 41 : return error;
364 :
365 138569 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
366 : {
367 : /* Maybe we can figure it out anyway. */
368 119 : error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
369 119 : if (error != DWFL_E_NOERROR
370 119 : && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
371 : return error;
372 : }
373 :
374 138528 : value = sym.st_value;
375 : }
376 :
377 : /* These are the types we can relocate. */
378 : #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
379 : DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
380 : DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
381 : size_t size;
382 138532 : switch (type)
383 : {
384 : #define DO_TYPE(NAME, Name) \
385 : case ELF_T_##NAME: \
386 : size = sizeof (GElf_##Name); \
387 : break
388 0 : TYPES;
389 : #undef DO_TYPE
390 : default:
391 : return DWFL_E_BADRELTYPE;
392 : }
393 :
394 138532 : if (offset > tdata->d_size || tdata->d_size - offset < size)
395 : return DWFL_E_BADRELOFF;
396 :
397 : #define DO_TYPE(NAME, Name) GElf_##Name Name;
398 : union { TYPES; } tmpbuf;
399 : #undef DO_TYPE
400 138532 : Elf_Data tmpdata =
401 : {
402 : .d_type = type,
403 : .d_buf = &tmpbuf,
404 : .d_size = size,
405 : .d_version = EV_CURRENT,
406 : };
407 277064 : Elf_Data rdata =
408 : {
409 : .d_type = type,
410 138532 : .d_buf = tdata->d_buf + offset,
411 : .d_size = size,
412 : .d_version = EV_CURRENT,
413 : };
414 :
415 : /* XXX check for overflow? */
416 138532 : if (addend)
417 : {
418 : /* For the addend form, we have the value already. */
419 133223 : value += *addend;
420 133223 : switch (type)
421 : {
422 : #define DO_TYPE(NAME, Name) \
423 : case ELF_T_##NAME: \
424 : tmpbuf.Name = value; \
425 : break
426 0 : TYPES;
427 : #undef DO_TYPE
428 : default:
429 0 : abort ();
430 : }
431 : }
432 : else
433 : {
434 : /* Extract the original value and apply the reloc. */
435 5309 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
436 5309 : ehdr->e_ident[EI_DATA]);
437 5309 : if (d == NULL)
438 : return DWFL_E_LIBELF;
439 5309 : assert (d == &tmpdata);
440 5309 : switch (type)
441 : {
442 : #define DO_TYPE(NAME, Name) \
443 : case ELF_T_##NAME: \
444 : tmpbuf.Name += (GElf_##Name) value; \
445 : break
446 0 : TYPES;
447 : #undef DO_TYPE
448 : default:
449 0 : abort ();
450 : }
451 : }
452 :
453 : /* Now convert the relocated datum back to the target
454 : format. This will write into rdata.d_buf, which
455 : points into the raw section data being relocated. */
456 138532 : Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
457 138532 : ehdr->e_ident[EI_DATA]);
458 138532 : if (s == NULL)
459 : return DWFL_E_LIBELF;
460 138532 : assert (s == &rdata);
461 :
462 : /* We have applied this relocation! */
463 : return DWFL_E_NOERROR;
464 : }
465 :
466 : static inline void
467 : check_badreltype (bool *first_badreltype,
468 : Dwfl_Module *mod,
469 : Dwfl_Error *result)
470 : {
471 153194 : if (*first_badreltype)
472 : {
473 406 : *first_badreltype = false;
474 406 : if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
475 : /* This might be because ebl_openbackend failed to find
476 : any libebl_CPU.so library. Diagnose that clearly. */
477 0 : *result = DWFL_E_UNKNOWN_MACHINE;
478 : }
479 : }
480 :
481 : static Dwfl_Error
482 528 : relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
483 : size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
484 : Elf_Scn *scn, GElf_Shdr *shdr,
485 : Elf_Scn *tscn, bool debugscn, bool partial)
486 : {
487 : /* First, fetch the name of the section these relocations apply to.
488 : Then try to decompress both relocation and target section. */
489 : GElf_Shdr tshdr_mem;
490 528 : GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
491 528 : if (tshdr == NULL)
492 : return DWFL_E_LIBELF;
493 :
494 528 : const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
495 528 : if (tname == NULL)
496 : return DWFL_E_LIBELF;
497 :
498 528 : if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
499 : /* This relocation section is not for a debugging section.
500 : Nothing to do here. */
501 : return DWFL_E_NOERROR;
502 :
503 406 : if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
504 4 : elf_compress_gnu (tscn, 0, 0);
505 :
506 406 : if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
507 14 : if (elf_compress (tscn, 0, 0) < 0)
508 : return DWFL_E_LIBELF;
509 :
510 : /* Reload Shdr in case section was just decompressed. */
511 406 : tshdr = gelf_getshdr (tscn, &tshdr_mem);
512 406 : if (tshdr == NULL)
513 : return DWFL_E_LIBELF;
514 :
515 406 : if (unlikely (tshdr->sh_type == SHT_NOBITS)
516 406 : || unlikely (tshdr->sh_size == 0))
517 : /* No contents to relocate. */
518 : return DWFL_E_NOERROR;
519 :
520 406 : const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
521 406 : if (sname == NULL)
522 : return DWFL_E_LIBELF;
523 :
524 406 : if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
525 0 : elf_compress_gnu (scn, 0, 0);
526 :
527 406 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
528 0 : if (elf_compress (scn, 0, 0) < 0)
529 : return DWFL_E_LIBELF;
530 :
531 : /* Reload Shdr in case section was just decompressed. */
532 : GElf_Shdr shdr_mem;
533 406 : shdr = gelf_getshdr (scn, &shdr_mem);
534 406 : if (shdr == NULL)
535 : return DWFL_E_LIBELF;
536 :
537 : /* Fetch the section data that needs the relocations applied. */
538 406 : Elf_Data *tdata = elf_rawdata (tscn, NULL);
539 406 : if (tdata == NULL)
540 : return DWFL_E_LIBELF;
541 :
542 : /* If either the section that needs the relocation applied, or the
543 : section that the relocations come from overlap one of the ehdrs,
544 : shdrs or phdrs data then we refuse to do the relocations. It
545 : isn't illegal for ELF section data to overlap the header data,
546 : but updating the (relocation) data might corrupt the in-memory
547 : libelf headers causing strange corruptions or errors. */
548 406 : size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
549 406 : if (unlikely (shdr->sh_offset < ehsize
550 : || tshdr->sh_offset < ehsize))
551 : return DWFL_E_BADELF;
552 :
553 406 : GElf_Off shdrs_start = ehdr->e_shoff;
554 : size_t shnums;
555 406 : if (elf_getshdrnum (relocated, &shnums) < 0)
556 : return DWFL_E_LIBELF;
557 : /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */
558 406 : size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
559 406 : GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
560 406 : if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size
561 : && shdr->sh_offset < shdrs_end)
562 : || (shdrs_start < tshdr->sh_offset + tshdr->sh_size
563 : && tshdr->sh_offset < shdrs_end)))
564 : return DWFL_E_BADELF;
565 :
566 406 : GElf_Off phdrs_start = ehdr->e_phoff;
567 : size_t phnums;
568 406 : if (elf_getphdrnum (relocated, &phnums) < 0)
569 : return DWFL_E_LIBELF;
570 406 : if (phdrs_start != 0 && phnums != 0)
571 : {
572 : /* Overflows will have been checked by elf_getphdrnum/get|rawdata. */
573 0 : size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
574 0 : GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
575 0 : if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size
576 : && shdr->sh_offset < phdrs_end)
577 : || (phdrs_start < tshdr->sh_offset + tshdr->sh_size
578 : && tshdr->sh_offset < phdrs_end)))
579 : return DWFL_E_BADELF;
580 : }
581 :
582 : /* Fetch the relocation section and apply each reloc in it. */
583 406 : Elf_Data *reldata = elf_getdata (scn, NULL);
584 406 : if (reldata == NULL)
585 : return DWFL_E_LIBELF;
586 :
587 406 : Dwfl_Error result = DWFL_E_NOERROR;
588 406 : bool first_badreltype = true;
589 :
590 406 : size_t sh_entsize
591 406 : = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
592 : 1, EV_CURRENT);
593 406 : size_t nrels = shdr->sh_size / sh_entsize;
594 406 : size_t complete = 0;
595 406 : if (shdr->sh_type == SHT_REL)
596 12577 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
597 : {
598 6273 : GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
599 6273 : if (r == NULL)
600 0 : return DWFL_E_LIBELF;
601 6273 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
602 : r->r_offset, NULL,
603 : GELF_R_TYPE (r->r_info),
604 6273 : GELF_R_SYM (r->r_info));
605 6273 : check_badreltype (&first_badreltype, mod, &result);
606 6273 : if (partial)
607 6273 : switch (result)
608 : {
609 : case DWFL_E_NOERROR:
610 : /* We applied the relocation. Elide it. */
611 : memset (&rel_mem, 0, sizeof rel_mem);
612 5309 : if (unlikely (gelf_update_rel (reldata, relidx, &rel_mem) == 0))
613 : return DWFL_E_LIBELF;
614 5309 : ++complete;
615 : break;
616 : case DWFL_E_BADRELTYPE:
617 : case DWFL_E_RELUNDEF:
618 : /* We couldn't handle this relocation. Skip it. */
619 964 : result = DWFL_E_NOERROR;
620 : break;
621 : default:
622 : break;
623 : }
624 : }
625 : else
626 294217 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
627 : {
628 146921 : GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
629 : &rela_mem);
630 146921 : if (r == NULL)
631 0 : return DWFL_E_LIBELF;
632 293842 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
633 146921 : r->r_offset, &r->r_addend,
634 : GELF_R_TYPE (r->r_info),
635 146921 : GELF_R_SYM (r->r_info));
636 146921 : check_badreltype (&first_badreltype, mod, &result);
637 146921 : if (partial)
638 146921 : switch (result)
639 : {
640 : case DWFL_E_NOERROR:
641 : /* We applied the relocation. Elide it. */
642 : memset (&rela_mem, 0, sizeof rela_mem);
643 133223 : if (unlikely (gelf_update_rela (reldata, relidx,
644 : &rela_mem) == 0))
645 : return DWFL_E_LIBELF;
646 133223 : ++complete;
647 : break;
648 : case DWFL_E_BADRELTYPE:
649 : case DWFL_E_RELUNDEF:
650 : /* We couldn't handle this relocation. Skip it. */
651 13698 : result = DWFL_E_NOERROR;
652 : break;
653 : default:
654 : break;
655 : }
656 : }
657 :
658 406 : if (likely (result == DWFL_E_NOERROR))
659 : {
660 406 : if (!partial || complete == nrels)
661 : /* Mark this relocation section as being empty now that we have
662 : done its work. This affects unstrip -R, so e.g. it emits an
663 : empty .rela.debug_info along with a .debug_info that has
664 : already been fully relocated. */
665 : nrels = 0;
666 104 : else if (complete != 0)
667 : {
668 : /* We handled some of the relocations but not all.
669 : We've zeroed out the ones we processed.
670 : Now remove them from the section. */
671 :
672 71 : size_t next = 0;
673 71 : if (shdr->sh_type == SHT_REL)
674 3094 : for (size_t relidx = 0; relidx < nrels; ++relidx)
675 : {
676 : GElf_Rel rel_mem;
677 1544 : GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
678 1544 : if (unlikely (r == NULL))
679 0 : return DWFL_E_LIBELF;
680 1544 : if (r->r_info != 0 || r->r_offset != 0)
681 : {
682 964 : if (next != relidx)
683 934 : if (unlikely (gelf_update_rel (reldata, next, r) == 0))
684 : return DWFL_E_LIBELF;
685 964 : ++next;
686 : }
687 : }
688 : else
689 32443 : for (size_t relidx = 0; relidx < nrels; ++relidx)
690 : {
691 : GElf_Rela rela_mem;
692 16189 : GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
693 16189 : if (unlikely (r == NULL))
694 0 : return DWFL_E_LIBELF;
695 16189 : if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
696 : {
697 13489 : if (next != relidx)
698 13060 : if (unlikely (gelf_update_rela (reldata, next, r) == 0))
699 : return DWFL_E_LIBELF;
700 13489 : ++next;
701 : }
702 : }
703 71 : nrels = next;
704 : }
705 :
706 406 : shdr->sh_size = reldata->d_size = nrels * sh_entsize;
707 406 : if (unlikely (gelf_update_shdr (scn, shdr) == 0))
708 : return DWFL_E_LIBELF;
709 : }
710 :
711 : return result;
712 : }
713 :
714 : Dwfl_Error
715 : internal_function
716 109 : __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
717 : {
718 109 : assert (mod->e_type == ET_REL);
719 :
720 : GElf_Ehdr ehdr_mem;
721 109 : const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
722 109 : if (ehdr == NULL)
723 : return DWFL_E_LIBELF;
724 :
725 : size_t d_shstrndx;
726 109 : if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
727 : return DWFL_E_LIBELF;
728 :
729 109 : RELOC_SYMTAB_CACHE (reloc_symtab);
730 :
731 : /* Look at each section in the debuginfo file, and process the
732 : relocation sections for debugging sections. */
733 109 : Dwfl_Error result = DWFL_E_NOERROR;
734 109 : Elf_Scn *scn = NULL;
735 2605 : while (result == DWFL_E_NOERROR
736 2496 : && (scn = elf_nextscn (debugfile, scn)) != NULL)
737 : {
738 : GElf_Shdr shdr_mem;
739 2387 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
740 2387 : if (unlikely (shdr == NULL))
741 0 : return DWFL_E_LIBELF;
742 :
743 2387 : if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
744 552 : && shdr->sh_size != 0)
745 : {
746 : /* It's a relocation section. */
747 :
748 526 : Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
749 526 : if (unlikely (tscn == NULL))
750 : result = DWFL_E_LIBELF;
751 : else
752 526 : result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
753 : &reloc_symtab, scn, shdr, tscn,
754 : debug, true /* partial always OK. */);
755 : }
756 : }
757 :
758 109 : return result;
759 : }
760 :
761 : Dwfl_Error
762 : internal_function
763 2 : __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
764 : Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
765 : {
766 : GElf_Ehdr ehdr_mem;
767 : GElf_Shdr shdr_mem;
768 :
769 2 : RELOC_SYMTAB_CACHE (reloc_symtab);
770 :
771 : size_t shstrndx;
772 2 : if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
773 : return DWFL_E_LIBELF;
774 :
775 2 : Dwfl_Error result = __libdwfl_module_getebl (mod);
776 2 : if (unlikely (result != DWFL_E_NOERROR))
777 : return result;
778 :
779 2 : GElf_Ehdr *ehdr = gelf_getehdr (relocated, &ehdr_mem);
780 2 : if (unlikely (ehdr == NULL))
781 : return DWFL_E_LIBELF;
782 :
783 2 : GElf_Shdr *shdr = gelf_getshdr (relocscn, &shdr_mem);
784 2 : if (unlikely (shdr == NULL))
785 : return DWFL_E_LIBELF;
786 :
787 2 : return relocate_section (mod, relocated, ehdr, shstrndx, &reloc_symtab,
788 : relocscn, shdr, tscn, false, partial);
789 : }
|