Branch data Line data Source code
1 : : /* Relocate debug information.
2 : : Copyright (C) 2005-2010 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
8 : : * the GNU Lesser General Public License as published by the Free
9 : : Software Foundation; either version 3 of the License, or (at
10 : : your option) any later version
11 : :
12 : : or
13 : :
14 : : * the GNU General Public License as published by the Free
15 : : Software Foundation; either version 2 of the License, or (at
16 : : your option) any later version
17 : :
18 : : or both in parallel, as here.
19 : :
20 : : elfutils is distributed in the hope that it will be useful, but
21 : : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : General Public License for more details.
24 : :
25 : : You should have received copies of the GNU General Public License and
26 : : the GNU Lesser General Public License along with this program. If
27 : : not, see <http://www.gnu.org/licenses/>. */
28 : :
29 : : #include "libdwflP.h"
30 : :
31 : : typedef uint8_t GElf_Byte;
32 : :
33 : : /* Adjust *VALUE to add the load address of the SHNDX section.
34 : : We update the section header in place to cache the result. */
35 : :
36 : : Dwfl_Error
37 : : internal_function
38 : 861309 : __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
39 : : Elf32_Word shndx, GElf_Addr *value)
40 : : {
41 [ - + ]: 861309 : assert (mod->e_type == ET_REL);
42 : :
43 : 861309 : Elf_Scn *refscn = elf_getscn (elf, shndx);
44 : 861309 : GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
45 [ + - ]: 861309 : if (refshdr == NULL)
46 : : return DWFL_E_LIBELF;
47 : :
48 [ + + ][ + + ]: 861309 : if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
49 : : {
50 : : /* This is a loaded section. Find its actual
51 : : address and update the section header. */
52 : :
53 [ + + ]: 95735 : if (*shstrndx == SHN_UNDEF
54 [ + - ]: 85702 : && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
55 : : return DWFL_E_LIBELF;
56 : :
57 : 95735 : const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
58 [ + - ]: 95735 : if (unlikely (name == NULL))
59 : : return DWFL_E_LIBELF;
60 : :
61 [ - + ]: 95735 : if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
62 : : name, shndx, refshdr,
63 : 95735 : &refshdr->sh_addr))
64 [ # # ]: 0 : return CBFAIL;
65 : :
66 [ - + ]: 95735 : if (refshdr->sh_addr == (Dwarf_Addr) -1l)
67 : : /* The callback indicated this section wasn't really loaded but we
68 : : don't really care. */
69 : 0 : refshdr->sh_addr = 0; /* Make no adjustment below. */
70 : :
71 : : /* Update the in-core file's section header to show the final
72 : : load address (or unloadedness). This serves as a cache,
73 : : so we won't get here again for the same section. */
74 [ + + ]: 95735 : if (likely (refshdr->sh_addr != 0)
75 [ + - ]: 4 : && unlikely (! gelf_update_shdr (refscn, refshdr)))
76 : : return DWFL_E_LIBELF;
77 : : }
78 : :
79 [ + + ]: 861309 : if (refshdr->sh_flags & SHF_ALLOC)
80 : : /* Apply the adjustment. */
81 : 861309 : *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
82 : :
83 : : return DWFL_E_NOERROR;
84 : : }
85 : :
86 : :
87 : : /* Cache used by relocate_getsym. */
88 : : struct reloc_symtab_cache
89 : : {
90 : : Elf *symelf;
91 : : Elf_Data *symdata;
92 : : Elf_Data *symxndxdata;
93 : : Elf_Data *symstrdata;
94 : : size_t symshstrndx;
95 : : size_t strtabndx;
96 : : };
97 : : #define RELOC_SYMTAB_CACHE(cache) \
98 : : struct reloc_symtab_cache cache = \
99 : : { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
100 : :
101 : : /* This is just doing dwfl_module_getsym, except that we must always use
102 : : the symbol table in RELOCATED itself when it has one, not MOD->symfile. */
103 : : static Dwfl_Error
104 : 32677 : relocate_getsym (Dwfl_Module *mod,
105 : : Elf *relocated, struct reloc_symtab_cache *cache,
106 : : int symndx, GElf_Sym *sym, GElf_Word *shndx)
107 : : {
108 [ + + ]: 32677 : if (cache->symdata == NULL)
109 : : {
110 [ + + ][ + + ]: 32 : if (mod->symfile == NULL || mod->symfile->elf != relocated)
111 : : {
112 : : /* We have to look up the symbol table in the file we are
113 : : relocating, if it has its own. These reloc sections refer to
114 : : the symbol table in this file, and a symbol table in the main
115 : : file might not match. However, some tools did produce ET_REL
116 : : .debug files with relocs but no symtab of their own. */
117 : : Elf_Scn *scn = NULL;
118 [ + + ]: 651 : while ((scn = elf_nextscn (relocated, scn)) != NULL)
119 : : {
120 : 624 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
121 [ + - ]: 624 : if (shdr != NULL)
122 [ + + - ]: 624 : switch (shdr->sh_type)
123 : : {
124 : : default:
125 : 597 : continue;
126 : : case SHT_SYMTAB:
127 : 27 : cache->symelf = relocated;
128 : 27 : cache->symdata = elf_getdata (scn, NULL);
129 : 27 : cache->strtabndx = shdr->sh_link;
130 [ + - ]: 27 : if (unlikely (cache->symdata == NULL))
131 : : return DWFL_E_LIBELF;
132 : : break;
133 : : case SHT_SYMTAB_SHNDX:
134 : 0 : cache->symxndxdata = elf_getdata (scn, NULL);
135 [ # # ]: 0 : if (unlikely (cache->symxndxdata == NULL))
136 : : return DWFL_E_LIBELF;
137 : : break;
138 : : }
139 [ + - ][ + - ]: 624 : if (cache->symdata != NULL && cache->symxndxdata != NULL)
140 : : break;
141 : : }
142 : : }
143 [ + + ]: 32 : if (cache->symdata == NULL)
144 : : {
145 : : /* We might not have looked for a symbol table file yet,
146 : : when coming from __libdwfl_relocate_section. */
147 [ - + ]: 5 : if (unlikely (mod->symfile == NULL)
148 [ # # ]: 0 : && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
149 : 0 : return dwfl_errno ();
150 : :
151 : : /* The symbol table we have already cached is the one from
152 : : the file being relocated, so it's what we need. Or else
153 : : this is an ET_REL .debug file with no .symtab of its own;
154 : : the symbols refer to the section indices in the main file. */
155 : 5 : cache->symelf = mod->symfile->elf;
156 : 5 : cache->symdata = mod->symdata;
157 : 5 : cache->symxndxdata = mod->symxndxdata;
158 : 5 : cache->symstrdata = mod->symstrdata;
159 : : }
160 : : }
161 : :
162 [ + - ]: 32677 : if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
163 : : symndx, sym, shndx) == NULL))
164 : : return DWFL_E_LIBELF;
165 : :
166 [ + - ]: 32677 : if (sym->st_shndx != SHN_XINDEX)
167 : 32677 : *shndx = sym->st_shndx;
168 : :
169 [ - + + ]: 32677 : switch (sym->st_shndx)
170 : : {
171 : : case SHN_ABS:
172 : : case SHN_UNDEF:
173 : : return DWFL_E_NOERROR;
174 : :
175 : : case SHN_COMMON:
176 : 0 : sym->st_value = 0; /* Value is size, not helpful. */
177 : 0 : return DWFL_E_NOERROR;
178 : : }
179 : :
180 : 32677 : return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
181 : 32668 : *shndx, &sym->st_value);
182 : : }
183 : :
184 : : /* Handle an undefined symbol. We really only support ET_REL for Linux
185 : : kernel modules, and offline archives. The behavior of the Linux module
186 : : loader is very simple and easy to mimic. It only matches magically
187 : : exported symbols, and we match any defined symbols. But we get the same
188 : : answer except when the module's symbols are undefined and would prevent
189 : : it from being loaded. */
190 : : static Dwfl_Error
191 : 9 : resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
192 : : GElf_Sym *sym, GElf_Word shndx)
193 : : {
194 : : /* First we need its name. */
195 [ + - ]: 9 : if (sym->st_name != 0)
196 : : {
197 [ + + ]: 9 : if (symtab->symstrdata == NULL)
198 : : {
199 : : /* Cache the strtab for this symtab. */
200 [ - + ][ # # ]: 4 : assert (referer->symfile == NULL
201 : : || referer->symfile->elf != symtab->symelf);
202 : 4 : symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
203 : : symtab->strtabndx),
204 : : NULL);
205 [ + - ]: 4 : if (unlikely (symtab->symstrdata == NULL))
206 : : return DWFL_E_LIBELF;
207 : : }
208 [ + - ]: 9 : if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
209 : : return DWFL_E_BADSTROFF;
210 : :
211 : 9 : const char *name = symtab->symstrdata->d_buf;
212 : 9 : name += sym->st_name;
213 : :
214 [ + + ]: 18 : for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
215 [ - + ]: 9 : if (m != referer)
216 : : {
217 : : /* Get this module's symtab.
218 : : If we got a fresh error reading the table, report it.
219 : : If we just have no symbols in this module, no harm done. */
220 [ # # ]: 0 : if (m->symdata == NULL
221 [ # # ]: 0 : && m->symerr == DWFL_E_NOERROR
222 [ # # ]: 0 : && INTUSE(dwfl_module_getsymtab) (m) < 0
223 [ # # ]: 0 : && m->symerr != DWFL_E_NO_SYMTAB)
224 : : return m->symerr;
225 : :
226 [ # # ]: 0 : for (size_t ndx = 1; ndx < m->syments; ++ndx)
227 : : {
228 : 0 : sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
229 : : ndx, sym, &shndx);
230 [ # # ]: 0 : if (unlikely (sym == NULL))
231 : : return DWFL_E_LIBELF;
232 [ # # ]: 0 : if (sym->st_shndx != SHN_XINDEX)
233 : 0 : shndx = sym->st_shndx;
234 : :
235 : : /* We are looking for a defined global symbol with a name. */
236 [ # # ]: 0 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON
237 [ # # ]: 0 : || GELF_ST_BIND (sym->st_info) == STB_LOCAL
238 [ # # ]: 0 : || sym->st_name == 0)
239 : 0 : continue;
240 : :
241 : : /* Get this candidate symbol's name. */
242 [ # # ]: 0 : if (unlikely (sym->st_name >= m->symstrdata->d_size))
243 : : return DWFL_E_BADSTROFF;
244 : 0 : const char *n = m->symstrdata->d_buf;
245 : 0 : n += sym->st_name;
246 : :
247 : : /* Does the name match? */
248 [ # # ]: 0 : if (strcmp (name, n))
249 : 0 : continue;
250 : :
251 : : /* We found it! */
252 [ # # ]: 0 : if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
253 : : return DWFL_E_NOERROR;
254 : :
255 [ # # ]: 0 : if (m->e_type != ET_REL)
256 : : {
257 : 0 : sym->st_value = dwfl_adjusted_st_value (m, sym->st_value);
258 : : return DWFL_E_NOERROR;
259 : : }
260 : :
261 : : /* In an ET_REL file, the symbol table values are relative
262 : : to the section, not to the module's load base. */
263 : 0 : size_t symshstrndx = SHN_UNDEF;
264 : 0 : return __libdwfl_relocate_value (m, m->symfile->elf,
265 : : &symshstrndx,
266 : 0 : shndx, &sym->st_value);
267 : : }
268 : : }
269 : : }
270 : :
271 : : return DWFL_E_RELUNDEF;
272 : : }
273 : :
274 : : static Dwfl_Error
275 : 150 : relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
276 : : size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
277 : : Elf_Scn *scn, GElf_Shdr *shdr,
278 : : Elf_Scn *tscn, bool debugscn, bool partial)
279 : : {
280 : : /* First, fetch the name of the section these relocations apply to. */
281 : : GElf_Shdr tshdr_mem;
282 : 150 : GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
283 : 150 : const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
284 [ + - ]: 150 : if (tname == NULL)
285 : : return DWFL_E_LIBELF;
286 : :
287 [ + - ][ + - ]: 150 : if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
288 : : /* No contents to relocate. */
289 : : return DWFL_E_NOERROR;
290 : :
291 [ + + ][ + + ]: 150 : if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
292 : : /* This relocation section is not for a debugging section.
293 : : Nothing to do here. */
294 : : return DWFL_E_NOERROR;
295 : :
296 : : /* Fetch the section data that needs the relocations applied. */
297 : 134 : Elf_Data *tdata = elf_rawdata (tscn, NULL);
298 [ + - ]: 134 : if (tdata == NULL)
299 : : return DWFL_E_LIBELF;
300 : :
301 : : /* Apply one relocation. Returns true for any invalid data. */
302 : 35660 : Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
303 : : int rtype, int symndx)
304 : : {
305 : : /* First see if this is a reloc we can handle.
306 : : If we are skipping it, don't bother resolving the symbol. */
307 : :
308 [ + - ]: 35660 : if (unlikely (rtype == 0))
309 : : /* In some odd situations, the linker can leave R_*_NONE relocs
310 : : behind. This is probably bogus ld -r behavior, but the only
311 : : cases it's known to appear in are harmless: DWARF data
312 : : referring to addresses in a section that has been discarded.
313 : : So we just pretend it's OK without further relocation. */
314 : : return DWFL_E_NOERROR;
315 : :
316 : 35660 : Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
317 [ + + ]: 35660 : if (unlikely (type == ELF_T_NUM))
318 : : return DWFL_E_BADRELTYPE;
319 : :
320 : : /* First, resolve the symbol to an absolute value. */
321 : : GElf_Addr value;
322 : :
323 [ + - ]: 32677 : if (symndx == STN_UNDEF)
324 : : /* When strip removes a section symbol referring to a
325 : : section moved into the debuginfo file, it replaces
326 : : that symbol index in relocs with STN_UNDEF. We
327 : : don't actually need the symbol, because those relocs
328 : : are always references relative to the nonallocated
329 : : debugging sections, which start at zero. */
330 : : value = 0;
331 : : else
332 : : {
333 : : GElf_Sym sym;
334 : : GElf_Word shndx;
335 : 32677 : Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
336 : : symndx, &sym, &shndx);
337 [ + - ]: 32677 : if (unlikely (error != DWFL_E_NOERROR))
338 : : return error;
339 : :
340 [ + + ]: 32677 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
341 : : {
342 : : /* Maybe we can figure it out anyway. */
343 : 9 : error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
344 [ + - ]: 9 : if (error != DWFL_E_NOERROR
345 [ + - ][ - + ]: 9 : && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
346 : : return error;
347 : : }
348 : :
349 : 32677 : value = sym.st_value;
350 : : }
351 : :
352 : : /* These are the types we can relocate. */
353 : : #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
354 : : DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
355 : : DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
356 : : size_t size;
357 [ - + + + : 32668 : switch (type)
+ - - ]
358 : : {
359 : : #define DO_TYPE(NAME, Name) \
360 : : case ELF_T_##NAME: \
361 : : size = sizeof (GElf_##Name); \
362 : : break
363 : 32668 : TYPES;
364 : : #undef DO_TYPE
365 : : default:
366 : : return DWFL_E_BADRELTYPE;
367 : : }
368 : :
369 [ + - ]: 32668 : if (offset + size > tdata->d_size)
370 : : return DWFL_E_BADRELOFF;
371 : :
372 : : #define DO_TYPE(NAME, Name) GElf_##Name Name;
373 : : union { TYPES; } tmpbuf;
374 : : #undef DO_TYPE
375 : 32668 : Elf_Data tmpdata =
376 : : {
377 : : .d_type = type,
378 : : .d_buf = &tmpbuf,
379 : : .d_size = size,
380 : : .d_version = EV_CURRENT,
381 : : };
382 : 65336 : Elf_Data rdata =
383 : : {
384 : : .d_type = type,
385 : 32668 : .d_buf = tdata->d_buf + offset,
386 : : .d_size = size,
387 : : .d_version = EV_CURRENT,
388 : : };
389 : :
390 : : /* XXX check for overflow? */
391 [ + + ]: 32668 : if (addend)
392 : : {
393 : : /* For the addend form, we have the value already. */
394 : 27675 : value += *addend;
395 [ - - + + : 27675 : switch (type)
+ + - ]
396 : : {
397 : : #define DO_TYPE(NAME, Name) \
398 : : case ELF_T_##NAME: \
399 : : tmpbuf.Name = value; \
400 : : break
401 : 27675 : TYPES;
402 : : #undef DO_TYPE
403 : : default:
404 : 0 : abort ();
405 : : }
406 : : }
407 : : else
408 : : {
409 : : /* Extract the original value and apply the reloc. */
410 : 4993 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
411 : 4993 : ehdr->e_ident[EI_DATA]);
412 [ + - ]: 4993 : if (d == NULL)
413 : : return DWFL_E_LIBELF;
414 [ - + ]: 4993 : assert (d == &tmpdata);
415 [ - - - + : 4993 : switch (type)
- - - ]
416 : : {
417 : : #define DO_TYPE(NAME, Name) \
418 : : case ELF_T_##NAME: \
419 : : tmpbuf.Name += (GElf_##Name) value; \
420 : : break
421 : 4993 : TYPES;
422 : : #undef DO_TYPE
423 : : default:
424 : 0 : abort ();
425 : : }
426 : : }
427 : :
428 : : /* Now convert the relocated datum back to the target
429 : : format. This will write into rdata.d_buf, which
430 : : points into the raw section data being relocated. */
431 : 32668 : Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
432 : 32668 : ehdr->e_ident[EI_DATA]);
433 [ + - ]: 32668 : if (s == NULL)
434 : : return DWFL_E_LIBELF;
435 [ - + ]: 35660 : assert (s == &rdata);
436 : :
437 : : /* We have applied this relocation! */
438 : : return DWFL_E_NOERROR;
439 : : }
440 : :
441 : : /* Fetch the relocation section and apply each reloc in it. */
442 : 134 : Elf_Data *reldata = elf_getdata (scn, NULL);
443 [ + - ]: 134 : if (reldata == NULL)
444 : : return DWFL_E_LIBELF;
445 : :
446 : 134 : Dwfl_Error result = DWFL_E_NOERROR;
447 : 134 : bool first_badreltype = true;
448 : 35660 : inline void check_badreltype (void)
449 : : {
450 [ + + ]: 35660 : if (first_badreltype)
451 : : {
452 : 134 : first_badreltype = false;
453 [ - + ]: 134 : if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
454 : : /* This might be because ebl_openbackend failed to find
455 : : any libebl_CPU.so library. Diagnose that clearly. */
456 : 0 : result = DWFL_E_UNKNOWN_MACHINE;
457 : : }
458 : 35660 : }
459 : :
460 : 134 : size_t nrels = shdr->sh_size / shdr->sh_entsize;
461 : 134 : size_t complete = 0;
462 [ + + ]: 134 : if (shdr->sh_type == SHT_REL)
463 [ + - ][ + + ]: 5504 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
464 : : {
465 : 5479 : GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
466 [ - + ]: 5479 : if (r == NULL)
467 : : return DWFL_E_LIBELF;
468 : 5479 : result = relocate (r->r_offset, NULL,
469 : : GELF_R_TYPE (r->r_info),
470 : 5479 : GELF_R_SYM (r->r_info));
471 : 5479 : check_badreltype ();
472 [ + + ]: 5479 : if (partial)
473 [ + + - ]: 4044 : switch (result)
474 : : {
475 : : case DWFL_E_NOERROR:
476 : : /* We applied the relocation. Elide it. */
477 : 3558 : memset (&rel_mem, 0, sizeof rel_mem);
478 : 3558 : gelf_update_rel (reldata, relidx, &rel_mem);
479 : 3558 : ++complete;
480 : 3558 : break;
481 : : case DWFL_E_BADRELTYPE:
482 : : case DWFL_E_RELUNDEF:
483 : : /* We couldn't handle this relocation. Skip it. */
484 : 486 : result = DWFL_E_NOERROR;
485 : 486 : break;
486 : : default:
487 : : break;
488 : : }
489 : : }
490 : : else
491 [ + - ][ + + ]: 30290 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
492 : : {
493 : 30181 : GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
494 : : &rela_mem);
495 [ - + ]: 30181 : if (r == NULL)
496 : : return DWFL_E_LIBELF;
497 : 30181 : result = relocate (r->r_offset, &r->r_addend,
498 : : GELF_R_TYPE (r->r_info),
499 : 30181 : GELF_R_SYM (r->r_info));
500 : 30181 : check_badreltype ();
501 [ + + ]: 30181 : if (partial)
502 [ + + - ]: 24106 : switch (result)
503 : : {
504 : : case DWFL_E_NOERROR:
505 : : /* We applied the relocation. Elide it. */
506 : 21600 : memset (&rela_mem, 0, sizeof rela_mem);
507 : 21600 : gelf_update_rela (reldata, relidx, &rela_mem);
508 : 21600 : ++complete;
509 : 21600 : break;
510 : : case DWFL_E_BADRELTYPE:
511 : : case DWFL_E_RELUNDEF:
512 : : /* We couldn't handle this relocation. Skip it. */
513 : 2506 : result = DWFL_E_NOERROR;
514 : 2506 : break;
515 : : default:
516 : : break;
517 : : }
518 : : }
519 : :
520 [ + - ]: 134 : if (likely (result == DWFL_E_NOERROR))
521 : : {
522 [ + + ]: 134 : if (!partial || complete == nrels)
523 : : /* Mark this relocation section as being empty now that we have
524 : : done its work. This affects unstrip -R, so e.g. it emits an
525 : : empty .rela.debug_info along with a .debug_info that has
526 : : already been fully relocated. */
527 : : nrels = 0;
528 [ + + ]: 25 : else if (complete != 0)
529 : : {
530 : : /* We handled some of the relocations but not all.
531 : : We've zeroed out the ones we processed.
532 : : Now remove them from the section. */
533 : :
534 : 16 : size_t next = 0;
535 [ + + ]: 16 : if (shdr->sh_type == SHT_REL)
536 [ + + ]: 782 : for (size_t relidx = 0; relidx < nrels; ++relidx)
537 : : {
538 : : GElf_Rel rel_mem;
539 : 778 : GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
540 [ + + ][ - + ]: 778 : if (r->r_info != 0 || r->r_offset != 0)
541 : : {
542 [ + + ]: 486 : if (next != relidx)
543 : 470 : gelf_update_rel (reldata, next, r);
544 : 486 : ++next;
545 : : }
546 : : }
547 : : else
548 [ + + ]: 3066 : for (size_t relidx = 0; relidx < nrels; ++relidx)
549 : : {
550 : : GElf_Rela rela_mem;
551 : 3054 : GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
552 [ + + ][ + - ]: 3054 : if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
[ - + ]
553 : : {
554 [ + + ]: 2463 : if (next != relidx)
555 : 2438 : gelf_update_rela (reldata, next, r);
556 : 2463 : ++next;
557 : : }
558 : : }
559 : 16 : nrels = next;
560 : : }
561 : :
562 : 134 : shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
563 : 134 : gelf_update_shdr (scn, shdr);
564 : : }
565 : :
566 : 150 : return result;
567 : : }
568 : :
569 : : Dwfl_Error
570 : : internal_function
571 : 37 : __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
572 : : {
573 [ - + ]: 37 : assert (mod->e_type == ET_REL);
574 : :
575 : : GElf_Ehdr ehdr_mem;
576 : 37 : const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
577 [ + - ]: 37 : if (ehdr == NULL)
578 : : return DWFL_E_LIBELF;
579 : :
580 : : size_t d_shstrndx;
581 [ + - ]: 37 : if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
582 : : return DWFL_E_LIBELF;
583 : :
584 : 37 : RELOC_SYMTAB_CACHE (reloc_symtab);
585 : :
586 : : /* Look at each section in the debuginfo file, and process the
587 : : relocation sections for debugging sections. */
588 : 37 : Dwfl_Error result = DWFL_E_NOERROR;
589 : 37 : Elf_Scn *scn = NULL;
590 [ + - ]: 803 : while (result == DWFL_E_NOERROR
591 [ + + ]: 803 : && (scn = elf_nextscn (debugfile, scn)) != NULL)
592 : : {
593 : : GElf_Shdr shdr_mem;
594 : 766 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
595 : :
596 [ + + ]: 766 : if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
597 [ + + ]: 154 : && shdr->sh_size != 0)
598 : : {
599 : : /* It's a relocation section. */
600 : :
601 : 148 : Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
602 [ + - ]: 148 : if (unlikely (tscn == NULL))
603 : : result = DWFL_E_LIBELF;
604 : : else
605 : 766 : result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
606 : : &reloc_symtab, scn, shdr, tscn,
607 : 148 : debug, !debug);
608 : : }
609 : : }
610 : :
611 : : return result;
612 : : }
613 : :
614 : : Dwfl_Error
615 : : internal_function
616 : 2 : __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
617 : : Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
618 : : {
619 : : GElf_Ehdr ehdr_mem;
620 : : GElf_Shdr shdr_mem;
621 : :
622 : 2 : RELOC_SYMTAB_CACHE (reloc_symtab);
623 : :
624 : : size_t shstrndx;
625 [ + - ]: 2 : if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
626 : : return DWFL_E_LIBELF;
627 : :
628 [ + - ]: 4 : return (__libdwfl_module_getebl (mod)
629 : 2 : ?: relocate_section (mod, relocated,
630 : 2 : gelf_getehdr (relocated, &ehdr_mem), shstrndx,
631 : : &reloc_symtab,
632 : : relocscn, gelf_getshdr (relocscn, &shdr_mem),
633 : : tscn, false, partial));
634 : 621162 : }
|