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