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 8358401 : __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 8358401 : if (shndx == 0)
49 : return DWFL_E_NOERROR;
50 :
51 8358401 : Elf_Scn *refscn = elf_getscn (elf, shndx);
52 8358401 : GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
53 8358401 : if (refshdr == NULL)
54 : return DWFL_E_LIBELF;
55 :
56 8358401 : 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 647750 : if (*shstrndx == SHN_UNDEF
62 564163 : && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
63 : return DWFL_E_LIBELF;
64 :
65 647750 : const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
66 647750 : if (unlikely (name == NULL))
67 : return DWFL_E_LIBELF;
68 :
69 1295500 : if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
70 : name, shndx, refshdr,
71 647750 : &refshdr->sh_addr))
72 0 : return CBFAIL;
73 :
74 647750 : 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 647750 : if (likely (refshdr->sh_addr != 0)
83 4 : && unlikely (! gelf_update_shdr (refscn, refshdr)))
84 : return DWFL_E_LIBELF;
85 : }
86 :
87 8358401 : if (refshdr->sh_flags & SHF_ALLOC)
88 : /* Apply the adjustment. */
89 15309218 : *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 157305 : relocate_getsym (Dwfl_Module *mod,
113 : Elf *relocated, struct reloc_symtab_cache *cache,
114 : int symndx, GElf_Sym *sym, GElf_Word *shndx)
115 : {
116 157305 : if (cache->symdata == NULL)
117 : {
118 134 : 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 592260 : while ((scn = elf_nextscn (relocated, scn)) != NULL)
127 : {
128 592159 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
129 592159 : if (shdr != NULL)
130 : {
131 : /* We need uncompressed data. */
132 1184318 : if ((shdr->sh_type == SHT_SYMTAB
133 592159 : || shdr->sh_type == SHT_SYMTAB_SHNDX)
134 101 : && (shdr->sh_flags & SHF_COMPRESSED) != 0)
135 0 : if (elf_compress (scn, 0, 0) < 0)
136 0 : return DWFL_E_LIBELF;
137 :
138 592159 : switch (shdr->sh_type)
139 : {
140 592058 : default:
141 592058 : continue;
142 101 : case SHT_SYMTAB:
143 101 : cache->symelf = relocated;
144 101 : cache->symdata = elf_getdata (scn, NULL);
145 101 : cache->strtabndx = shdr->sh_link;
146 101 : if (unlikely (cache->symdata == NULL))
147 : return DWFL_E_LIBELF;
148 : break;
149 0 : 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 0 : }
156 101 : if (cache->symdata != NULL && cache->symxndxdata != NULL)
157 : break;
158 : }
159 : }
160 134 : 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 157305 : if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
180 : symndx, sym, shndx) == NULL))
181 : return DWFL_E_LIBELF;
182 :
183 157305 : if (sym->st_shndx != SHN_XINDEX)
184 157305 : *shndx = sym->st_shndx;
185 :
186 157305 : switch (sym->st_shndx)
187 : {
188 : case SHN_ABS:
189 : case SHN_UNDEF:
190 : return DWFL_E_NOERROR;
191 :
192 78 : case SHN_COMMON:
193 78 : sym->st_value = 0; /* Value is size, not helpful. */
194 78 : return DWFL_E_NOERROR;
195 : }
196 :
197 157174 : return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
198 157174 : *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 131 : 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 131 : if (sym->st_name != 0)
213 : {
214 131 : if (symtab->symstrdata == NULL)
215 : {
216 : /* Cache the strtab for this symtab. */
217 18 : assert (referer->symfile == NULL
218 : || referer->symfile->elf != symtab->symelf);
219 :
220 18 : Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
221 18 : if (scn == NULL)
222 0 : return DWFL_E_LIBELF;
223 :
224 : GElf_Shdr shdr_mem;
225 18 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
226 18 : if (shdr == NULL)
227 : return DWFL_E_LIBELF;
228 :
229 18 : if (symtab->symshstrndx == SHN_UNDEF
230 10 : && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
231 : return DWFL_E_LIBELF;
232 :
233 18 : const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
234 18 : shdr->sh_name);
235 18 : if (sname == NULL)
236 : return DWFL_E_LIBELF;
237 :
238 : /* If the section is already decompressed, that isn't an error. */
239 18 : if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
240 0 : elf_compress_gnu (scn, 0, 0);
241 :
242 18 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
243 0 : if (elf_compress (scn, 0, 0) < 0)
244 : return DWFL_E_LIBELF;
245 :
246 18 : symtab->symstrdata = elf_getdata (scn, NULL);
247 18 : if (unlikely (symtab->symstrdata == NULL
248 : || symtab->symstrdata->d_buf == NULL))
249 : return DWFL_E_LIBELF;
250 : }
251 131 : if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
252 : return DWFL_E_BADSTROFF;
253 :
254 131 : const char *name = symtab->symstrdata->d_buf;
255 131 : name += sym->st_name;
256 :
257 262 : for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
258 131 : 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 177545 : 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 177545 : 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 177545 : int addsub = 0;
342 177545 : Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype, &addsub);
343 177545 : if (unlikely (type == ELF_T_NUM))
344 : return DWFL_E_BADRELTYPE;
345 :
346 : /* First, resolve the symbol to an absolute value. */
347 : GElf_Addr value;
348 :
349 157309 : if (symndx == STN_UNDEF)
350 : /* When strip removes a section symbol referring to a
351 : section moved into the debuginfo file, it replaces
352 : that symbol index in relocs with STN_UNDEF. We
353 : don't actually need the symbol, because those relocs
354 : are always references relative to the nonallocated
355 : debugging sections, which start at zero. */
356 : value = 0;
357 : else
358 : {
359 : GElf_Sym sym;
360 : GElf_Word shndx;
361 157305 : Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
362 : symndx, &sym, &shndx);
363 157305 : if (unlikely (error != DWFL_E_NOERROR))
364 53 : return error;
365 :
366 157305 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
367 : {
368 : /* Maybe we can figure it out anyway. */
369 131 : error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
370 131 : if (error != DWFL_E_NOERROR
371 131 : && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
372 : return error;
373 : }
374 :
375 157252 : value = sym.st_value;
376 : }
377 :
378 : /* These are the types we can relocate. */
379 : #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
380 : DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
381 : DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
382 : size_t size;
383 157256 : switch (type)
384 : {
385 : #define DO_TYPE(NAME, Name) \
386 : case ELF_T_##NAME: \
387 : if (addsub != 0 && addend == NULL) \
388 : /* These do not make sense with SHT_REL. */ \
389 : return DWFL_E_BADRELTYPE; \
390 : size = sizeof (GElf_##Name); \
391 : break
392 0 : TYPES;
393 : #undef DO_TYPE
394 : default:
395 : return DWFL_E_BADRELTYPE;
396 : }
397 :
398 157256 : if (offset > tdata->d_size || tdata->d_size - offset < size)
399 : return DWFL_E_BADRELOFF;
400 :
401 : #define DO_TYPE(NAME, Name) GElf_##Name Name;
402 : union { TYPES; } tmpbuf;
403 : #undef DO_TYPE
404 157256 : Elf_Data tmpdata =
405 : {
406 : .d_type = type,
407 : .d_buf = &tmpbuf,
408 : .d_size = size,
409 : .d_version = EV_CURRENT,
410 : };
411 314512 : Elf_Data rdata =
412 : {
413 : .d_type = type,
414 157256 : .d_buf = tdata->d_buf + offset,
415 : .d_size = size,
416 : .d_version = EV_CURRENT,
417 : };
418 :
419 : /* XXX check for overflow? */
420 157256 : if (addend)
421 : {
422 : /* For the addend form, we have the value already. */
423 144834 : value += *addend;
424 : /* For ADD/SUB relocations we need to fetch the section
425 : contents. */
426 144834 : if (addsub != 0)
427 : {
428 68 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
429 68 : ehdr->e_ident[EI_DATA]);
430 68 : if (d == NULL)
431 : return DWFL_E_LIBELF;
432 68 : assert (d == &tmpdata);
433 : }
434 144834 : switch (type)
435 : {
436 : #define DO_TYPE(NAME, Name) \
437 : case ELF_T_##NAME: \
438 : if (addsub != 0) \
439 : tmpbuf.Name += value * addsub; \
440 : else \
441 : tmpbuf.Name = value; \
442 : break
443 0 : TYPES;
444 : #undef DO_TYPE
445 0 : default:
446 0 : abort ();
447 : }
448 : }
449 : else
450 : {
451 : /* Extract the original value and apply the reloc. */
452 12422 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
453 12422 : ehdr->e_ident[EI_DATA]);
454 12422 : if (d == NULL)
455 : return DWFL_E_LIBELF;
456 12422 : assert (d == &tmpdata);
457 12422 : switch (type)
458 : {
459 : #define DO_TYPE(NAME, Name) \
460 : case ELF_T_##NAME: \
461 : tmpbuf.Name += (GElf_##Name) value; \
462 : break
463 0 : TYPES;
464 : #undef DO_TYPE
465 0 : default:
466 0 : abort ();
467 : }
468 : }
469 :
470 : /* Now convert the relocated datum back to the target
471 : format. This will write into rdata.d_buf, which
472 : points into the raw section data being relocated. */
473 157256 : Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
474 157256 : ehdr->e_ident[EI_DATA]);
475 157256 : if (s == NULL)
476 : return DWFL_E_LIBELF;
477 157256 : assert (s == &rdata);
478 :
479 : /* We have applied this relocation! */
480 : return DWFL_E_NOERROR;
481 : }
482 :
483 : static inline void
484 : check_badreltype (bool *first_badreltype,
485 : Dwfl_Module *mod,
486 : Dwfl_Error *result)
487 : {
488 177545 : if (*first_badreltype)
489 : {
490 642 : *first_badreltype = false;
491 642 : if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
492 : /* This might be because ebl_openbackend failed to find
493 : any libebl_CPU.so library. Diagnose that clearly. */
494 0 : *result = DWFL_E_UNKNOWN_MACHINE;
495 : }
496 : }
497 :
498 : static Dwfl_Error
499 836 : relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
500 : size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
501 : Elf_Scn *scn, GElf_Shdr *shdr,
502 : Elf_Scn *tscn, bool debugscn, bool partial)
503 : {
504 : /* First, fetch the name of the section these relocations apply to.
505 : Then try to decompress both relocation and target section. */
506 : GElf_Shdr tshdr_mem;
507 836 : GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
508 836 : if (tshdr == NULL)
509 : return DWFL_E_LIBELF;
510 :
511 836 : const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
512 836 : if (tname == NULL)
513 : return DWFL_E_LIBELF;
514 :
515 836 : if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
516 : /* This relocation section is not for a debugging section.
517 : Nothing to do here. */
518 : return DWFL_E_NOERROR;
519 :
520 642 : if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
521 12 : elf_compress_gnu (tscn, 0, 0);
522 :
523 642 : if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
524 22 : if (elf_compress (tscn, 0, 0) < 0)
525 : return DWFL_E_LIBELF;
526 :
527 : /* Reload Shdr in case section was just decompressed. */
528 642 : tshdr = gelf_getshdr (tscn, &tshdr_mem);
529 642 : if (tshdr == NULL)
530 : return DWFL_E_LIBELF;
531 :
532 642 : if (unlikely (tshdr->sh_type == SHT_NOBITS)
533 642 : || unlikely (tshdr->sh_size == 0))
534 : /* No contents to relocate. */
535 : return DWFL_E_NOERROR;
536 :
537 642 : const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
538 642 : if (sname == NULL)
539 : return DWFL_E_LIBELF;
540 :
541 642 : if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
542 0 : elf_compress_gnu (scn, 0, 0);
543 :
544 642 : if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
545 0 : if (elf_compress (scn, 0, 0) < 0)
546 : return DWFL_E_LIBELF;
547 :
548 : /* Reload Shdr in case section was just decompressed. */
549 : GElf_Shdr shdr_mem;
550 642 : shdr = gelf_getshdr (scn, &shdr_mem);
551 642 : if (shdr == NULL)
552 : return DWFL_E_LIBELF;
553 :
554 : /* Fetch the section data that needs the relocations applied. */
555 642 : Elf_Data *tdata = elf_rawdata (tscn, NULL);
556 642 : if (tdata == NULL)
557 : return DWFL_E_LIBELF;
558 :
559 : /* If either the section that needs the relocation applied, or the
560 : section that the relocations come from overlap one of the ehdrs,
561 : shdrs or phdrs data then we refuse to do the relocations. It
562 : isn't illegal for ELF section data to overlap the header data,
563 : but updating the (relocation) data might corrupt the in-memory
564 : libelf headers causing strange corruptions or errors. */
565 642 : size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
566 642 : if (unlikely (shdr->sh_offset < ehsize
567 : || tshdr->sh_offset < ehsize))
568 : return DWFL_E_BADELF;
569 :
570 642 : GElf_Off shdrs_start = ehdr->e_shoff;
571 : size_t shnums;
572 642 : if (elf_getshdrnum (relocated, &shnums) < 0)
573 : return DWFL_E_LIBELF;
574 : /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */
575 642 : size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
576 642 : GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
577 642 : if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size
578 : && shdr->sh_offset < shdrs_end)
579 : || (shdrs_start < tshdr->sh_offset + tshdr->sh_size
580 : && tshdr->sh_offset < shdrs_end)))
581 : return DWFL_E_BADELF;
582 :
583 642 : GElf_Off phdrs_start = ehdr->e_phoff;
584 : size_t phnums;
585 642 : if (elf_getphdrnum (relocated, &phnums) < 0)
586 : return DWFL_E_LIBELF;
587 642 : if (phdrs_start != 0 && phnums != 0)
588 : {
589 : /* Overflows will have been checked by elf_getphdrnum/get|rawdata. */
590 0 : size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
591 0 : GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
592 0 : if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size
593 : && shdr->sh_offset < phdrs_end)
594 : || (phdrs_start < tshdr->sh_offset + tshdr->sh_size
595 : && tshdr->sh_offset < phdrs_end)))
596 : return DWFL_E_BADELF;
597 : }
598 :
599 : /* Fetch the relocation section and apply each reloc in it. */
600 642 : Elf_Data *reldata = elf_getdata (scn, NULL);
601 642 : if (reldata == NULL)
602 : return DWFL_E_LIBELF;
603 :
604 642 : Dwfl_Error result = DWFL_E_NOERROR;
605 642 : bool first_badreltype = true;
606 :
607 642 : size_t sh_entsize
608 642 : = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA,
609 : 1, EV_CURRENT);
610 642 : size_t nrels = shdr->sh_size / sh_entsize;
611 642 : size_t complete = 0;
612 642 : if (shdr->sh_type == SHT_REL)
613 28811 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
614 : {
615 14365 : GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
616 14365 : if (r == NULL)
617 0 : return DWFL_E_LIBELF;
618 14365 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
619 : r->r_offset, NULL,
620 : GELF_R_TYPE (r->r_info),
621 14365 : GELF_R_SYM (r->r_info));
622 28730 : check_badreltype (&first_badreltype, mod, &result);
623 14365 : if (partial)
624 14365 : switch (result)
625 : {
626 12422 : case DWFL_E_NOERROR:
627 : /* We applied the relocation. Elide it. */
628 12422 : memset (&rel_mem, 0, sizeof rel_mem);
629 12422 : if (unlikely (gelf_update_rel (reldata, relidx, &rel_mem) == 0))
630 : return DWFL_E_LIBELF;
631 12422 : ++complete;
632 12422 : break;
633 1943 : case DWFL_E_BADRELTYPE:
634 : case DWFL_E_RELUNDEF:
635 : /* We couldn't handle this relocation. Skip it. */
636 1943 : result = DWFL_E_NOERROR;
637 1943 : break;
638 : default:
639 : break;
640 : }
641 0 : }
642 : else
643 326921 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
644 : {
645 163180 : GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
646 : &rela_mem);
647 163180 : if (r == NULL)
648 0 : return DWFL_E_LIBELF;
649 326360 : result = relocate (mod, relocated, reloc_symtab, tdata, ehdr,
650 163180 : r->r_offset, &r->r_addend,
651 : GELF_R_TYPE (r->r_info),
652 163180 : GELF_R_SYM (r->r_info));
653 326360 : check_badreltype (&first_badreltype, mod, &result);
654 163180 : if (partial)
655 163180 : switch (result)
656 : {
657 144834 : case DWFL_E_NOERROR:
658 : /* We applied the relocation. Elide it. */
659 144834 : memset (&rela_mem, 0, sizeof rela_mem);
660 144834 : if (unlikely (gelf_update_rela (reldata, relidx,
661 : &rela_mem) == 0))
662 : return DWFL_E_LIBELF;
663 144834 : ++complete;
664 144834 : break;
665 18346 : case DWFL_E_BADRELTYPE:
666 : case DWFL_E_RELUNDEF:
667 : /* We couldn't handle this relocation. Skip it. */
668 18346 : result = DWFL_E_NOERROR;
669 18346 : break;
670 : default:
671 : break;
672 : }
673 0 : }
674 :
675 642 : if (likely (result == DWFL_E_NOERROR))
676 : {
677 642 : if (!partial || complete == nrels)
678 : /* Mark this relocation section as being empty now that we have
679 : done its work. This affects unstrip -R, so e.g. it emits an
680 : empty .rela.debug_info along with a .debug_info that has
681 : already been fully relocated. */
682 : nrels = 0;
683 161 : else if (complete != 0)
684 : {
685 : /* We handled some of the relocations but not all.
686 : We've zeroed out the ones we processed.
687 : Now remove them from the section. */
688 :
689 50 : size_t next = 0;
690 50 : if (shdr->sh_type == SHT_REL)
691 6188 : for (size_t relidx = 0; relidx < nrels; ++relidx)
692 : {
693 : GElf_Rel rel_mem;
694 3088 : GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
695 3088 : if (unlikely (r == NULL))
696 0 : return DWFL_E_LIBELF;
697 3088 : if (r->r_info != 0 || r->r_offset != 0)
698 : {
699 1928 : if (next != relidx)
700 1868 : if (unlikely (gelf_update_rel (reldata, next, r) == 0))
701 : return DWFL_E_LIBELF;
702 1928 : ++next;
703 : }
704 : }
705 : else
706 302 : for (size_t relidx = 0; relidx < nrels; ++relidx)
707 : {
708 : GElf_Rela rela_mem;
709 132 : GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
710 132 : if (unlikely (r == NULL))
711 0 : return DWFL_E_LIBELF;
712 132 : if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
713 : {
714 59 : if (next != relidx)
715 56 : if (unlikely (gelf_update_rela (reldata, next, r) == 0))
716 : return DWFL_E_LIBELF;
717 59 : ++next;
718 : }
719 : }
720 : nrels = next;
721 : }
722 :
723 642 : shdr->sh_size = reldata->d_size = nrels * sh_entsize;
724 642 : if (unlikely (gelf_update_shdr (scn, shdr) == 0))
725 : return DWFL_E_LIBELF;
726 : }
727 :
728 : return result;
729 : }
730 :
731 : Dwfl_Error
732 : internal_function
733 156 : __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
734 : {
735 156 : assert (mod->e_type == ET_REL);
736 :
737 : GElf_Ehdr ehdr_mem;
738 156 : const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
739 156 : if (ehdr == NULL)
740 : return DWFL_E_LIBELF;
741 :
742 : size_t d_shstrndx;
743 156 : if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
744 : return DWFL_E_LIBELF;
745 :
746 156 : RELOC_SYMTAB_CACHE (reloc_symtab);
747 :
748 : /* Look at each section in the debuginfo file, and process the
749 : relocation sections for debugging sections. */
750 156 : Dwfl_Error result = DWFL_E_NOERROR;
751 156 : Elf_Scn *scn = NULL;
752 790385 : while (result == DWFL_E_NOERROR
753 790229 : && (scn = elf_nextscn (debugfile, scn)) != NULL)
754 : {
755 : GElf_Shdr shdr_mem;
756 790073 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
757 790073 : if (unlikely (shdr == NULL))
758 0 : return DWFL_E_LIBELF;
759 :
760 790073 : if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
761 860 : && shdr->sh_size != 0)
762 : {
763 : /* It's a relocation section. */
764 :
765 834 : Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
766 834 : if (unlikely (tscn == NULL))
767 : result = DWFL_E_LIBELF;
768 : else
769 834 : result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
770 : &reloc_symtab, scn, shdr, tscn,
771 : debug, true /* partial always OK. */);
772 : }
773 : }
774 :
775 : return result;
776 : }
777 :
778 : Dwfl_Error
779 : internal_function
780 2 : __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
781 : Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
782 : {
783 : GElf_Ehdr ehdr_mem;
784 : GElf_Shdr shdr_mem;
785 :
786 2 : RELOC_SYMTAB_CACHE (reloc_symtab);
787 :
788 : size_t shstrndx;
789 2 : if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
790 : return DWFL_E_LIBELF;
791 :
792 2 : Dwfl_Error result = __libdwfl_module_getebl (mod);
793 2 : if (unlikely (result != DWFL_E_NOERROR))
794 : return result;
795 :
796 2 : GElf_Ehdr *ehdr = gelf_getehdr (relocated, &ehdr_mem);
797 2 : if (unlikely (ehdr == NULL))
798 : return DWFL_E_LIBELF;
799 :
800 2 : GElf_Shdr *shdr = gelf_getshdr (relocscn, &shdr_mem);
801 2 : if (unlikely (shdr == NULL))
802 : return DWFL_E_LIBELF;
803 :
804 2 : return relocate_section (mod, relocated, ehdr, shstrndx, &reloc_symtab,
805 : relocscn, shdr, tscn, false, partial);
806 : }
|