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