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 8365952 : __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 8365952 : if (shndx == 0)
50 : return DWFL_E_NOERROR;
51 :
52 8365952 : Elf_Scn *refscn = elf_getscn (elf, shndx);
53 8365952 : GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
54 8365952 : if (refshdr == NULL)
55 : return DWFL_E_LIBELF;
56 :
57 8365952 : 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 648355 : if (*shstrndx == SHN_UNDEF
63 564702 : && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
64 : return DWFL_E_LIBELF;
65 :
66 648355 : const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
67 648355 : if (unlikely (name == NULL))
68 : return DWFL_E_LIBELF;
69 :
70 1296710 : if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
71 : name, shndx, refshdr,
72 648355 : &refshdr->sh_addr))
73 0 : return CBFAIL;
74 :
75 648355 : 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 648355 : if (likely (refshdr->sh_addr != 0)
84 4 : && unlikely (! gelf_update_shdr (refscn, refshdr)))
85 : return DWFL_E_LIBELF;
86 : }
87 :
88 8365952 : if (refshdr->sh_flags & SHF_ALLOC)
89 : /* Apply the adjustment. */
90 15323658 : *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 157261 : relocate_getsym (Dwfl_Module *mod,
114 : Elf *relocated, struct reloc_symtab_cache *cache,
115 : int symndx, GElf_Sym *sym, GElf_Word *shndx)
116 : {
117 157261 : if (cache->symdata == NULL)
118 : {
119 134 : 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 592260 : while ((scn = elf_nextscn (relocated, scn)) != NULL)
128 : {
129 592159 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
130 592159 : if (shdr != NULL)
131 : {
132 : /* We need uncompressed data. */
133 1184318 : if ((shdr->sh_type == SHT_SYMTAB
134 592159 : || shdr->sh_type == SHT_SYMTAB_SHNDX)
135 101 : && (shdr->sh_flags & SHF_COMPRESSED) != 0)
136 0 : if (elf_compress (scn, 0, 0) < 0)
137 0 : return DWFL_E_LIBELF;
138 :
139 592159 : switch (shdr->sh_type)
140 : {
141 592058 : default:
142 592058 : continue;
143 101 : case SHT_SYMTAB:
144 101 : cache->symelf = relocated;
145 101 : cache->symdata = elf_getdata (scn, NULL);
146 101 : cache->strtabndx = shdr->sh_link;
147 101 : 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 101 : if (cache->symdata != NULL && cache->symxndxdata != NULL)
158 : break;
159 : }
160 : }
161 134 : 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 33 : 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 33 : cache->symelf = mod->symfile->elf;
174 33 : cache->symdata = mod->symdata;
175 33 : cache->symxndxdata = mod->symxndxdata;
176 33 : cache->symstrdata = mod->symstrdata;
177 : }
178 : }
179 :
180 157261 : if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
181 : symndx, sym, shndx) == NULL))
182 : return DWFL_E_LIBELF;
183 :
184 157261 : if (sym->st_shndx != SHN_XINDEX)
185 157261 : *shndx = sym->st_shndx;
186 :
187 157261 : 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 157130 : return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
199 157130 : *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 131 : 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 131 : if (sym->st_name != 0)
214 : {
215 131 : if (symtab->symstrdata == NULL)
216 : {
217 : /* Cache the strtab for this symtab. */
218 18 : assert (referer->symfile == NULL
219 : || referer->symfile->elf != symtab->symelf);
220 :
221 18 : Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
222 18 : if (scn == NULL)
223 0 : return DWFL_E_LIBELF;
224 :
225 : GElf_Shdr shdr_mem;
226 18 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
227 18 : if (shdr == NULL)
228 : return DWFL_E_LIBELF;
229 :
230 18 : if (symtab->symshstrndx == SHN_UNDEF
231 10 : && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
232 : return DWFL_E_LIBELF;
233 :
234 18 : const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
235 18 : shdr->sh_name);
236 18 : if (sname == NULL)
237 : return DWFL_E_LIBELF;
238 :
239 : /* If the section is already decompressed, that isn't an error. */
240 18 : if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
241 0 : elf_compress_gnu (scn, 0, 0);
242 :
243 18 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
244 0 : if (elf_compress (scn, 0, 0) < 0)
245 : return DWFL_E_LIBELF;
246 :
247 18 : symtab->symstrdata = elf_getdata (scn, NULL);
248 18 : if (unlikely (symtab->symstrdata == NULL
249 : || symtab->symstrdata->d_buf == NULL))
250 : return DWFL_E_LIBELF;
251 : }
252 131 : if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
253 : return DWFL_E_BADSTROFF;
254 :
255 131 : const char *name = symtab->symstrdata->d_buf;
256 131 : name += sym->st_name;
257 :
258 262 : for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
259 131 : 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 : 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 0 : 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 177483 : 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 177483 : 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 177483 : int addsub = 0;
343 177483 : Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype, &addsub);
344 177483 : 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 157265 : 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 157261 : Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
363 : symndx, &sym, &shndx);
364 157261 : if (unlikely (error != DWFL_E_NOERROR))
365 53 : return error;
366 :
367 157261 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
368 : {
369 : /* Maybe we can figure it out anyway. */
370 131 : error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
371 131 : if (error != DWFL_E_NOERROR
372 131 : && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
373 : return error;
374 : }
375 :
376 157208 : 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 157212 : 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 157212 : 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 157212 : Elf_Data tmpdata =
406 : {
407 : .d_type = type,
408 : .d_buf = &tmpbuf,
409 : .d_size = size,
410 : .d_version = EV_CURRENT,
411 : };
412 314424 : Elf_Data rdata =
413 : {
414 : .d_type = type,
415 157212 : .d_buf = tdata->d_buf + offset,
416 : .d_size = size,
417 : .d_version = EV_CURRENT,
418 : };
419 :
420 : /* XXX check for overflow? */
421 157212 : if (addend)
422 : {
423 : /* For the addend form, we have the value already. */
424 144790 : value += *addend;
425 : /* For ADD/SUB relocations we need to fetch the section
426 : contents. */
427 144790 : if (addsub != 0)
428 : {
429 68 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
430 68 : ehdr->e_ident[EI_DATA]);
431 68 : if (d == NULL)
432 : return DWFL_E_LIBELF;
433 68 : assert (d == &tmpdata);
434 : }
435 144790 : 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 12422 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
454 12422 : ehdr->e_ident[EI_DATA]);
455 12422 : if (d == NULL)
456 : return DWFL_E_LIBELF;
457 12422 : assert (d == &tmpdata);
458 12422 : 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 157212 : Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
475 157212 : ehdr->e_ident[EI_DATA]);
476 157212 : if (s == NULL)
477 : return DWFL_E_LIBELF;
478 157212 : assert (s == &rdata);
479 :
480 : /* We have applied this relocation! */
481 : return DWFL_E_NOERROR;
482 : }
483 :
484 : static inline void
485 : check_badreltype (bool *first_badreltype,
486 : Dwfl_Module *mod,
487 : Dwfl_Error *result)
488 : {
489 177483 : if (*first_badreltype)
490 : {
491 642 : *first_badreltype = false;
492 642 : 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 : }
498 :
499 : static Dwfl_Error
500 836 : 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 836 : GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
509 836 : if (tshdr == NULL)
510 : return DWFL_E_LIBELF;
511 :
512 836 : const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
513 836 : if (tname == NULL)
514 : return DWFL_E_LIBELF;
515 :
516 836 : 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 642 : if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
522 12 : elf_compress_gnu (tscn, 0, 0);
523 :
524 642 : 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 642 : tshdr = gelf_getshdr (tscn, &tshdr_mem);
530 642 : if (tshdr == NULL)
531 : return DWFL_E_LIBELF;
532 :
533 642 : if (unlikely (tshdr->sh_type == SHT_NOBITS)
534 642 : || unlikely (tshdr->sh_size == 0))
535 : /* No contents to relocate. */
536 : return DWFL_E_NOERROR;
537 :
538 642 : const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
539 642 : if (sname == NULL)
540 : return DWFL_E_LIBELF;
541 :
542 642 : if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
543 0 : elf_compress_gnu (scn, 0, 0);
544 :
545 642 : 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 : GElf_Shdr shdr_mem;
551 642 : shdr = gelf_getshdr (scn, &shdr_mem);
552 642 : if (shdr == NULL)
553 : return DWFL_E_LIBELF;
554 :
555 : /* Fetch the section data that needs the relocations applied. */
556 642 : Elf_Data *tdata = elf_rawdata (tscn, NULL);
557 642 : 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 642 : if (relocated->map_address != NULL)
571 : {
572 642 : size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
573 642 : if (unlikely (shdr->sh_offset < ehsize
574 : || tshdr->sh_offset < ehsize))
575 0 : return DWFL_E_BADELF;
576 :
577 642 : GElf_Off shdrs_start = ehdr->e_shoff;
578 : size_t shnums;
579 642 : if (elf_getshdrnum (relocated, &shnums) < 0)
580 : return DWFL_E_LIBELF;
581 : /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */
582 642 : size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
583 642 : GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
584 642 : 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 642 : 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 642 : GElf_Off phdrs_start = ehdr->e_phoff;
595 : size_t phnums;
596 642 : if (elf_getphdrnum (relocated, &phnums) < 0)
597 : return DWFL_E_LIBELF;
598 642 : 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 642 : Elf_Data *reldata = elf_getdata (scn, NULL);
617 642 : if (reldata == NULL)
618 : return DWFL_E_LIBELF;
619 :
620 642 : Dwfl_Error result = DWFL_E_NOERROR;
621 642 : bool first_badreltype = true;
622 :
623 642 : size_t sh_entsize
624 642 : = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
625 : 1, EV_CURRENT);
626 642 : size_t nrels = shdr->sh_size / sh_entsize;
627 642 : size_t complete = 0;
628 642 : if (shdr->sh_type == SHT_REL)
629 28811 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
630 : {
631 14365 : GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
632 14365 : if (r == NULL)
633 0 : return DWFL_E_LIBELF;
634 14365 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
635 : r->r_offset, NULL,
636 : GELF_R_TYPE (r->r_info),
637 14365 : GELF_R_SYM (r->r_info));
638 28730 : check_badreltype (&first_badreltype, mod, &result);
639 14365 : if (partial)
640 14365 : switch (result)
641 : {
642 12422 : case DWFL_E_NOERROR:
643 : /* We applied the relocation. Elide it. */
644 12422 : memset (&rel_mem, 0, sizeof rel_mem);
645 12422 : if (unlikely (gelf_update_rel (reldata, relidx, &rel_mem) == 0))
646 : return DWFL_E_LIBELF;
647 12422 : ++complete;
648 12422 : 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 326797 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
660 : {
661 163118 : GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
662 : &rela_mem);
663 163118 : if (r == NULL)
664 0 : return DWFL_E_LIBELF;
665 326236 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
666 163118 : r->r_offset, &r->r_addend,
667 : GELF_R_TYPE (r->r_info),
668 163118 : GELF_R_SYM (r->r_info));
669 326236 : check_badreltype (&first_badreltype, mod, &result);
670 163118 : if (partial)
671 163118 : switch (result)
672 : {
673 144790 : case DWFL_E_NOERROR:
674 : /* We applied the relocation. Elide it. */
675 144790 : memset (&rela_mem, 0, sizeof rela_mem);
676 144790 : if (unlikely (gelf_update_rela (reldata, relidx,
677 : &rela_mem) == 0))
678 : return DWFL_E_LIBELF;
679 144790 : ++complete;
680 144790 : break;
681 18328 : case DWFL_E_BADRELTYPE:
682 : case DWFL_E_RELUNDEF:
683 : /* We couldn't handle this relocation. Skip it. */
684 18328 : result = DWFL_E_NOERROR;
685 18328 : break;
686 : default:
687 : break;
688 : }
689 0 : }
690 :
691 642 : if (likely (result == DWFL_E_NOERROR))
692 : {
693 642 : 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 161 : 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 50 : size_t next = 0;
706 50 : if (shdr->sh_type == SHT_REL)
707 6188 : for (size_t relidx = 0; relidx < nrels; ++relidx)
708 : {
709 : 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 302 : for (size_t relidx = 0; relidx < nrels; ++relidx)
723 : {
724 : GElf_Rela rela_mem;
725 132 : GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
726 132 : if (unlikely (r == NULL))
727 0 : return DWFL_E_LIBELF;
728 132 : if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
729 : {
730 59 : if (next != relidx)
731 56 : if (unlikely (gelf_update_rela (reldata, next, r) == 0))
732 : return DWFL_E_LIBELF;
733 59 : ++next;
734 : }
735 : }
736 : nrels = next;
737 : }
738 :
739 642 : shdr->sh_size = reldata->d_size = nrels * sh_entsize;
740 642 : 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
749 160 : __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
750 : {
751 160 : assert (mod->e_type == ET_REL);
752 :
753 : GElf_Ehdr ehdr_mem;
754 160 : const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
755 160 : if (ehdr == NULL)
756 : return DWFL_E_LIBELF;
757 :
758 : size_t d_shstrndx;
759 160 : if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
760 : return DWFL_E_LIBELF;
761 :
762 160 : 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 160 : Dwfl_Error result = DWFL_E_NOERROR;
767 160 : Elf_Scn *scn = NULL;
768 790421 : while (result == DWFL_E_NOERROR
769 790261 : && (scn = elf_nextscn (debugfile, scn)) != NULL)
770 : {
771 : GElf_Shdr shdr_mem;
772 790101 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
773 790101 : if (unlikely (shdr == NULL))
774 0 : return DWFL_E_LIBELF;
775 :
776 790101 : if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
777 860 : && shdr->sh_size != 0)
778 : {
779 : /* It's a relocation section. */
780 :
781 834 : Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
782 834 : if (unlikely (tscn == NULL))
783 : result = DWFL_E_LIBELF;
784 : else
785 834 : 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 : GElf_Ehdr ehdr_mem;
800 : GElf_Shdr shdr_mem;
801 :
802 2 : RELOC_SYMTAB_CACHE (reloc_symtab);
803 :
804 : 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 : }
|