Line data Source code
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
43 10765147 : __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 10765147 : if (shndx == 0)
50 : return DWFL_E_NOERROR;
51 :
52 10765147 : Elf_Scn *refscn = elf_getscn (elf, shndx);
53 10765147 : GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
54 10765147 : if (refshdr == NULL)
55 : return DWFL_E_LIBELF;
56 :
57 10765147 : 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 829557 : if (*shstrndx == SHN_UNDEF
63 729748 : && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
64 : return DWFL_E_LIBELF;
65 :
66 829557 : const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
67 829557 : if (unlikely (name == NULL))
68 : return DWFL_E_LIBELF;
69 :
70 829557 : if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
71 : name, shndx, refshdr,
72 829557 : &refshdr->sh_addr))
73 0 : return CBFAIL;
74 :
75 829557 : 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 0 : 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 829557 : if (likely (refshdr->sh_addr != 0)
84 4 : && unlikely (! gelf_update_shdr (refscn, refshdr)))
85 : return DWFL_E_LIBELF;
86 : }
87 :
88 10765147 : if (refshdr->sh_flags & SHF_ALLOC)
89 : /* Apply the adjustment. */
90 19820558 : *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
113 185591 : relocate_getsym (Dwfl_Module *mod,
114 : Elf *relocated, struct reloc_symtab_cache *cache,
115 : int symndx, GElf_Sym *sym, GElf_Word *shndx)
116 : {
117 185591 : if (cache->symdata == NULL)
118 : {
119 144 : 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 592408 : while ((scn = elf_nextscn (relocated, scn)) != NULL)
128 : {
129 592299 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
130 592299 : if (shdr != NULL)
131 : {
132 : /* We need uncompressed data. */
133 1184598 : if ((shdr->sh_type == SHT_SYMTAB
134 592299 : || shdr->sh_type == SHT_SYMTAB_SHNDX)
135 109 : && (shdr->sh_flags & SHF_COMPRESSED) != 0)
136 0 : if (elf_compress (scn, 0, 0) < 0)
137 0 : return DWFL_E_LIBELF;
138 :
139 592299 : switch (shdr->sh_type)
140 : {
141 592190 : default:
142 592190 : continue;
143 109 : case SHT_SYMTAB:
144 109 : cache->symelf = relocated;
145 109 : cache->symdata = elf_getdata (scn, NULL);
146 109 : cache->strtabndx = shdr->sh_link;
147 109 : if (unlikely (cache->symdata == NULL))
148 : return DWFL_E_LIBELF;
149 : break;
150 0 : case SHT_SYMTAB_SHNDX:
151 0 : cache->symxndxdata = elf_getdata (scn, NULL);
152 0 : if (unlikely (cache->symxndxdata == NULL))
153 : return DWFL_E_LIBELF;
154 : break;
155 : }
156 0 : }
157 109 : if (cache->symdata != NULL && cache->symxndxdata != NULL)
158 : break;
159 : }
160 : }
161 144 : 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 35 : if (unlikely (mod->symfile == NULL)
166 0 : && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
167 0 : 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 35 : cache->symelf = mod->symfile->elf;
174 35 : cache->symdata = mod->symdata;
175 35 : cache->symxndxdata = mod->symxndxdata;
176 35 : cache->symstrdata = mod->symstrdata;
177 : }
178 : }
179 :
180 185591 : if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
181 : symndx, sym, shndx) == NULL))
182 : return DWFL_E_LIBELF;
183 :
184 185591 : if (sym->st_shndx != SHN_XINDEX)
185 185591 : *shndx = sym->st_shndx;
186 :
187 185591 : switch (sym->st_shndx)
188 : {
189 : case SHN_ABS:
190 : case SHN_UNDEF:
191 : return DWFL_E_NOERROR;
192 :
193 78 : case SHN_COMMON:
194 78 : sym->st_value = 0; /* Value is size, not helpful. */
195 78 : return DWFL_E_NOERROR;
196 : }
197 :
198 370912 : return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
199 185456 : *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
209 135 : 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 135 : if (sym->st_name != 0)
214 : {
215 135 : if (symtab->symstrdata == NULL)
216 : {
217 : /* Cache the strtab for this symtab. */
218 20 : assert (referer->symfile == NULL
219 : || referer->symfile->elf != symtab->symelf);
220 :
221 20 : Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
222 20 : if (scn == NULL)
223 0 : return DWFL_E_LIBELF;
224 :
225 20 : GElf_Shdr shdr_mem;
226 20 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
227 20 : if (shdr == NULL)
228 : return DWFL_E_LIBELF;
229 :
230 20 : if (symtab->symshstrndx == SHN_UNDEF
231 12 : && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
232 : return DWFL_E_LIBELF;
233 :
234 60 : const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
235 20 : shdr->sh_name);
236 20 : if (sname == NULL)
237 : return DWFL_E_LIBELF;
238 :
239 : /* If the section is already decompressed, that isn't an error. */
240 20 : if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
241 0 : elf_compress_gnu (scn, 0, 0);
242 :
243 20 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
244 0 : if (elf_compress (scn, 0, 0) < 0)
245 : return DWFL_E_LIBELF;
246 :
247 20 : symtab->symstrdata = elf_getdata (scn, NULL);
248 20 : if (unlikely (symtab->symstrdata == NULL
249 : || symtab->symstrdata->d_buf == NULL))
250 : return DWFL_E_LIBELF;
251 : }
252 135 : if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
253 : return DWFL_E_BADSTROFF;
254 :
255 135 : const char *name = symtab->symstrdata->d_buf;
256 135 : name += sym->st_name;
257 :
258 270 : for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
259 135 : 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 0 : if (m->symdata == NULL
265 0 : && m->symerr == DWFL_E_NOERROR
266 0 : && INTUSE(dwfl_module_getsymtab) (m) < 0
267 0 : && m->symerr != DWFL_E_NO_SYMTAB)
268 0 : return m->symerr;
269 :
270 0 : for (size_t ndx = 1; ndx < m->syments; ++ndx)
271 : {
272 0 : sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
273 : ndx, sym, &shndx);
274 0 : if (unlikely (sym == NULL))
275 0 : return DWFL_E_LIBELF;
276 0 : if (sym->st_shndx != SHN_XINDEX)
277 0 : shndx = sym->st_shndx;
278 :
279 : /* We are looking for a defined global symbol with a name. */
280 0 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON
281 0 : || GELF_ST_BIND (sym->st_info) == STB_LOCAL
282 0 : || sym->st_name == 0)
283 0 : continue;
284 :
285 : /* Get this candidate symbol's name. */
286 0 : if (unlikely (sym->st_name >= m->symstrdata->d_size))
287 : return DWFL_E_BADSTROFF;
288 0 : const char *n = m->symstrdata->d_buf;
289 0 : n += sym->st_name;
290 :
291 : /* Does the name match? */
292 0 : if (strcmp (name, n))
293 : continue;
294 :
295 : /* We found it! */
296 0 : if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
297 : return DWFL_E_NOERROR;
298 :
299 0 : if (m->e_type != ET_REL)
300 : {
301 0 : sym->st_value = dwfl_adjusted_st_value (m, m->symfile->elf,
302 : sym->st_value);
303 0 : 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 0 : size_t symshstrndx = SHN_UNDEF;
309 0 : return __libdwfl_relocate_value (m, m->symfile->elf,
310 : &symshstrndx,
311 0 : 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
321 0 : 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 0 : 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 0 : return DWFL_E_NOERROR;
341 :
342 0 : int addsub = 0;
343 0 : Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype, &addsub);
344 0 : if (unlikely (type == ELF_T_NUM))
345 0 : return DWFL_E_BADRELTYPE;
346 :
347 : /* First, resolve the symbol to an absolute value. */
348 0 : GElf_Addr value;
349 :
350 0 : 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 0 : GElf_Sym sym;
361 0 : GElf_Word shndx;
362 0 : Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
363 : symndx, &sym, &shndx);
364 0 : if (unlikely (error != DWFL_E_NOERROR))
365 0 : return error;
366 :
367 0 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
368 : {
369 : /* Maybe we can figure it out anyway. */
370 0 : error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
371 0 : if (error != DWFL_E_NOERROR
372 0 : && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
373 0 : return error;
374 : }
375 :
376 0 : 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 0 : size_t size;
384 0 : 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 0 : TYPES;
394 : #undef DO_TYPE
395 : default:
396 : return DWFL_E_BADRELTYPE;
397 : }
398 :
399 0 : if (offset > tdata->d_size || tdata->d_size - offset < size)
400 0 : return DWFL_E_BADRELOFF;
401 :
402 : #define DO_TYPE(NAME, Name) GElf_##Name Name;
403 0 : union { TYPES; } tmpbuf;
404 : #undef DO_TYPE
405 0 : Elf_Data tmpdata =
406 : {
407 : .d_type = type,
408 : .d_buf = &tmpbuf,
409 : .d_size = size,
410 : .d_version = EV_CURRENT,
411 : };
412 0 : Elf_Data rdata =
413 : {
414 : .d_type = type,
415 0 : .d_buf = tdata->d_buf + offset,
416 : .d_size = size,
417 : .d_version = EV_CURRENT,
418 : };
419 :
420 : /* XXX check for overflow? */
421 0 : if (addend)
422 : {
423 : /* For the addend form, we have the value already. */
424 0 : value += *addend;
425 : /* For ADD/SUB relocations we need to fetch the section
426 : contents. */
427 0 : if (addsub != 0)
428 : {
429 0 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
430 0 : ehdr->e_ident[EI_DATA]);
431 0 : if (d == NULL)
432 0 : return DWFL_E_LIBELF;
433 0 : assert (d == &tmpdata);
434 : }
435 0 : 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 0 : TYPES;
445 : #undef DO_TYPE
446 0 : default:
447 0 : abort ();
448 : }
449 : }
450 : else
451 : {
452 : /* Extract the original value and apply the reloc. */
453 0 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
454 0 : ehdr->e_ident[EI_DATA]);
455 0 : if (d == NULL)
456 0 : return DWFL_E_LIBELF;
457 0 : assert (d == &tmpdata);
458 0 : switch (type)
459 : {
460 : #define DO_TYPE(NAME, Name) \
461 : case ELF_T_##NAME: \
462 : tmpbuf.Name += (GElf_##Name) value; \
463 : break
464 0 : TYPES;
465 : #undef DO_TYPE
466 0 : default:
467 0 : 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 0 : Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
475 0 : ehdr->e_ident[EI_DATA]);
476 0 : if (s == NULL)
477 0 : return DWFL_E_LIBELF;
478 0 : assert (s == &rdata);
479 :
480 : /* We have applied this relocation! */
481 : return DWFL_E_NOERROR;
482 : }
483 :
484 : static inline void
485 0 : check_badreltype (bool *first_badreltype,
486 : Dwfl_Module *mod,
487 : Dwfl_Error *result)
488 : {
489 0 : if (*first_badreltype)
490 : {
491 674 : *first_badreltype = false;
492 674 : 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 0 : *result = DWFL_E_UNKNOWN_MACHINE;
496 : }
497 0 : }
498 :
499 : static Dwfl_Error
500 877 : 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 877 : GElf_Shdr tshdr_mem;
508 877 : GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
509 877 : if (tshdr == NULL)
510 : return DWFL_E_LIBELF;
511 :
512 877 : const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
513 877 : if (tname == NULL)
514 : return DWFL_E_LIBELF;
515 :
516 877 : 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 674 : if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
522 12 : elf_compress_gnu (tscn, 0, 0);
523 :
524 674 : if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
525 22 : if (elf_compress (tscn, 0, 0) < 0)
526 : return DWFL_E_LIBELF;
527 :
528 : /* Reload Shdr in case section was just decompressed. */
529 674 : tshdr = gelf_getshdr (tscn, &tshdr_mem);
530 674 : if (tshdr == NULL)
531 : return DWFL_E_LIBELF;
532 :
533 674 : if (unlikely (tshdr->sh_type == SHT_NOBITS)
534 674 : || unlikely (tshdr->sh_size == 0))
535 : /* No contents to relocate. */
536 : return DWFL_E_NOERROR;
537 :
538 674 : const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
539 674 : if (sname == NULL)
540 : return DWFL_E_LIBELF;
541 :
542 674 : if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
543 0 : elf_compress_gnu (scn, 0, 0);
544 :
545 674 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
546 0 : if (elf_compress (scn, 0, 0) < 0)
547 : return DWFL_E_LIBELF;
548 :
549 : /* Reload Shdr in case section was just decompressed. */
550 674 : GElf_Shdr shdr_mem;
551 674 : shdr = gelf_getshdr (scn, &shdr_mem);
552 674 : if (shdr == NULL)
553 : return DWFL_E_LIBELF;
554 :
555 : /* Fetch the section data that needs the relocations applied. */
556 674 : Elf_Data *tdata = elf_rawdata (tscn, NULL);
557 674 : 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 674 : if (relocated->map_address != NULL)
571 : {
572 674 : size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
573 674 : if (unlikely (shdr->sh_offset < ehsize
574 : || tshdr->sh_offset < ehsize))
575 0 : return DWFL_E_BADELF;
576 :
577 674 : GElf_Off shdrs_start = ehdr->e_shoff;
578 674 : size_t shnums;
579 674 : if (elf_getshdrnum (relocated, &shnums) < 0)
580 : return DWFL_E_LIBELF;
581 : /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */
582 674 : size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
583 674 : GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
584 674 : if (unlikely (shdrs_start < shdr->sh_offset + shdr->sh_size
585 : && shdr->sh_offset < shdrs_end))
586 0 : if ((scn->flags & ELF_F_MALLOCED) == 0)
587 : return DWFL_E_BADELF;
588 :
589 674 : if (unlikely (shdrs_start < tshdr->sh_offset + tshdr->sh_size
590 : && tshdr->sh_offset < shdrs_end))
591 0 : if ((tscn->flags & ELF_F_MALLOCED) == 0)
592 : return DWFL_E_BADELF;
593 :
594 674 : GElf_Off phdrs_start = ehdr->e_phoff;
595 674 : size_t phnums;
596 674 : if (elf_getphdrnum (relocated, &phnums) < 0)
597 : return DWFL_E_LIBELF;
598 674 : if (phdrs_start != 0 && phnums != 0)
599 : {
600 : /* Overflows will have been checked by elf_getphdrnum/get|rawdata. */
601 0 : size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
602 0 : GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
603 0 : if (unlikely (phdrs_start < shdr->sh_offset + shdr->sh_size
604 : && shdr->sh_offset < phdrs_end))
605 0 : if ((scn->flags & ELF_F_MALLOCED) == 0)
606 : return DWFL_E_BADELF;
607 :
608 0 : if (unlikely (phdrs_start < tshdr->sh_offset + tshdr->sh_size
609 : && tshdr->sh_offset < phdrs_end))
610 0 : 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 674 : Elf_Data *reldata = elf_getdata (scn, NULL);
617 674 : if (reldata == NULL)
618 : return DWFL_E_LIBELF;
619 :
620 674 : Dwfl_Error result = DWFL_E_NOERROR;
621 674 : bool first_badreltype = true;
622 :
623 674 : size_t sh_entsize
624 1262 : = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
625 : 1, EV_CURRENT);
626 674 : size_t nrels = shdr->sh_size / sh_entsize;
627 674 : size_t complete = 0;
628 674 : if (shdr->sh_type == SHT_REL)
629 15886 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
630 : {
631 15800 : GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
632 15800 : if (r == NULL)
633 0 : return DWFL_E_LIBELF;
634 47400 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
635 : r->r_offset, NULL,
636 : GELF_R_TYPE (r->r_info),
637 15800 : GELF_R_SYM (r->r_info));
638 15800 : check_badreltype (&first_badreltype, mod, &result);
639 15800 : if (partial)
640 15800 : switch (result)
641 : {
642 : case DWFL_E_NOERROR:
643 : /* We applied the relocation. Elide it. */
644 13857 : memset (&rel_mem, 0, sizeof rel_mem);
645 13857 : if (unlikely (gelf_update_rel (reldata, relidx, &rel_mem) == 0))
646 : return DWFL_E_LIBELF;
647 13857 : ++complete;
648 13857 : break;
649 1943 : case DWFL_E_BADRELTYPE:
650 : case DWFL_E_RELUNDEF:
651 : /* We couldn't handle this relocation. Skip it. */
652 1943 : result = DWFL_E_NOERROR;
653 1943 : break;
654 : default:
655 : break;
656 : }
657 0 : }
658 : else
659 190497 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
660 : {
661 189909 : GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
662 : &rela_mem);
663 189909 : if (r == NULL)
664 0 : return DWFL_E_LIBELF;
665 759636 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
666 189909 : r->r_offset, &r->r_addend,
667 : GELF_R_TYPE (r->r_info),
668 189909 : GELF_R_SYM (r->r_info));
669 189909 : check_badreltype (&first_badreltype, mod, &result);
670 189909 : if (partial)
671 189909 : switch (result)
672 : {
673 : case DWFL_E_NOERROR:
674 : /* We applied the relocation. Elide it. */
675 171681 : memset (&rela_mem, 0, sizeof rela_mem);
676 171681 : if (unlikely (gelf_update_rela (reldata, relidx,
677 : &rela_mem) == 0))
678 : return DWFL_E_LIBELF;
679 171681 : ++complete;
680 171681 : break;
681 18228 : case DWFL_E_BADRELTYPE:
682 : case DWFL_E_RELUNDEF:
683 : /* We couldn't handle this relocation. Skip it. */
684 18228 : result = DWFL_E_NOERROR;
685 18228 : break;
686 : default:
687 : break;
688 : }
689 0 : }
690 :
691 674 : if (likely (result == DWFL_E_NOERROR))
692 : {
693 674 : 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 163 : 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 52 : size_t next = 0;
706 52 : if (shdr->sh_type == SHT_REL)
707 3100 : for (size_t relidx = 0; relidx < nrels; ++relidx)
708 : {
709 3088 : GElf_Rel rel_mem;
710 3088 : GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
711 3088 : if (unlikely (r == NULL))
712 0 : return DWFL_E_LIBELF;
713 3088 : if (r->r_info != 0 || r->r_offset != 0)
714 : {
715 1928 : if (next != relidx)
716 1868 : if (unlikely (gelf_update_rel (reldata, next, r) == 0))
717 : return DWFL_E_LIBELF;
718 1928 : ++next;
719 : }
720 : }
721 : else
722 184 : for (size_t relidx = 0; relidx < nrels; ++relidx)
723 : {
724 144 : GElf_Rela rela_mem;
725 144 : GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
726 144 : if (unlikely (r == NULL))
727 0 : return DWFL_E_LIBELF;
728 144 : if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
729 : {
730 67 : if (next != relidx)
731 62 : if (unlikely (gelf_update_rela (reldata, next, r) == 0))
732 : return DWFL_E_LIBELF;
733 67 : ++next;
734 : }
735 : }
736 : nrels = next;
737 : }
738 :
739 674 : shdr->sh_size = reldata->d_size = nrels * sh_entsize;
740 674 : if (unlikely (gelf_update_shdr (scn, shdr) == 0))
741 0 : return DWFL_E_LIBELF;
742 : }
743 :
744 : return result;
745 : }
746 :
747 : Dwfl_Error
748 : internal_function
749 174 : __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
750 : {
751 174 : assert (mod->e_type == ET_REL);
752 :
753 174 : GElf_Ehdr ehdr_mem;
754 174 : const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
755 174 : if (ehdr == NULL)
756 : return DWFL_E_LIBELF;
757 :
758 174 : size_t d_shstrndx;
759 174 : if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
760 : return DWFL_E_LIBELF;
761 :
762 174 : 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 174 : Dwfl_Error result = DWFL_E_NOERROR;
767 174 : Elf_Scn *scn = NULL;
768 790506 : while (result == DWFL_E_NOERROR
769 790506 : && (scn = elf_nextscn (debugfile, scn)) != NULL)
770 : {
771 790332 : GElf_Shdr shdr_mem;
772 790332 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
773 790332 : if (unlikely (shdr == NULL))
774 0 : return DWFL_E_LIBELF;
775 :
776 790332 : if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
777 901 : && shdr->sh_size != 0)
778 : {
779 : /* It's a relocation section. */
780 :
781 875 : Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
782 875 : if (unlikely (tscn == NULL))
783 : result = DWFL_E_LIBELF;
784 : else
785 875 : 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
796 2 : __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
797 : Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
798 : {
799 2 : GElf_Ehdr ehdr_mem;
800 2 : GElf_Shdr shdr_mem;
801 :
802 2 : RELOC_SYMTAB_CACHE (reloc_symtab);
803 :
804 2 : size_t shstrndx;
805 2 : if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
806 : return DWFL_E_LIBELF;
807 :
808 2 : Dwfl_Error result = __libdwfl_module_getebl (mod);
809 2 : if (unlikely (result != DWFL_E_NOERROR))
810 : return result;
811 :
812 2 : GElf_Ehdr *ehdr = gelf_getehdr (relocated, &ehdr_mem);
813 2 : if (unlikely (ehdr == NULL))
814 : return DWFL_E_LIBELF;
815 :
816 2 : GElf_Shdr *shdr = gelf_getshdr (relocscn, &shdr_mem);
817 2 : if (unlikely (shdr == NULL))
818 : return DWFL_E_LIBELF;
819 :
820 2 : return relocate_section (mod, relocated, ehdr, shstrndx, &reloc_symtab,
821 : relocscn, shdr, tscn, false, partial);
822 : }
|