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