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