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 : 878113 : __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
39 : : Elf32_Word shndx, GElf_Addr *value)
40 : : {
41 [ - + ]: 878113 : assert (mod->e_type == ET_REL);
42 : :
43 : 878113 : Elf_Scn *refscn = elf_getscn (elf, shndx);
44 : 878113 : GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
45 [ + - ]: 878113 : if (refshdr == NULL)
46 : : return DWFL_E_LIBELF;
47 : :
48 [ + + ][ + + ]: 878113 : 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 [ + + ]: 98059 : if (*shstrndx == SHN_UNDEF
54 [ + - ]: 87702 : && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
55 : : return DWFL_E_LIBELF;
56 : :
57 : 98059 : const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
58 [ + - ]: 98059 : if (unlikely (name == NULL))
59 : : return DWFL_E_LIBELF;
60 : :
61 [ - + ]: 98059 : if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
62 : : name, shndx, refshdr,
63 : 98059 : &refshdr->sh_addr))
64 [ # # ]: 0 : return CBFAIL;
65 : :
66 [ - + ]: 98059 : 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 [ + + ]: 98059 : if (likely (refshdr->sh_addr != 0)
75 [ + - ]: 4 : && unlikely (! gelf_update_shdr (refscn, refshdr)))
76 : : return DWFL_E_LIBELF;
77 : : }
78 : :
79 [ + + ]: 878113 : if (refshdr->sh_flags & SHF_ALLOC)
80 : : /* Apply the adjustment. */
81 : 878113 : *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 : 32981 : relocate_getsym (Dwfl_Module *mod,
105 : : Elf *relocated, struct reloc_symtab_cache *cache,
106 : : int symndx, GElf_Sym *sym, GElf_Word *shndx)
107 : : {
108 [ + + ]: 32981 : 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 [ + - ]: 32981 : if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
163 : : symndx, sym, shndx) == NULL))
164 : : return DWFL_E_LIBELF;
165 : :
166 [ + - ]: 32981 : if (sym->st_shndx != SHN_XINDEX)
167 : 32981 : *shndx = sym->st_shndx;
168 : :
169 [ - + + ]: 32981 : 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 : 32981 : return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
181 : 32972 : *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, m->symfile,
258 : : sym->st_value);
259 : : return DWFL_E_NOERROR;
260 : : }
261 : :
262 : : /* In an ET_REL file, the symbol table values are relative
263 : : to the section, not to the module's load base. */
264 : 0 : size_t symshstrndx = SHN_UNDEF;
265 : 0 : return __libdwfl_relocate_value (m, m->symfile->elf,
266 : : &symshstrndx,
267 : 0 : shndx, &sym->st_value);
268 : : }
269 : : }
270 : : }
271 : :
272 : : return DWFL_E_RELUNDEF;
273 : : }
274 : :
275 : : static Dwfl_Error
276 : 150 : relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
277 : : size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
278 : : Elf_Scn *scn, GElf_Shdr *shdr,
279 : : Elf_Scn *tscn, bool debugscn, bool partial)
280 : : {
281 : : /* First, fetch the name of the section these relocations apply to. */
282 : : GElf_Shdr tshdr_mem;
283 : 150 : GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
284 : 150 : const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
285 [ + - ]: 150 : if (tname == NULL)
286 : : return DWFL_E_LIBELF;
287 : :
288 [ + - ][ + - ]: 150 : if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
289 : : /* No contents to relocate. */
290 : : return DWFL_E_NOERROR;
291 : :
292 [ + + ][ + + ]: 150 : if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
293 : : /* This relocation section is not for a debugging section.
294 : : Nothing to do here. */
295 : : return DWFL_E_NOERROR;
296 : :
297 : : /* Fetch the section data that needs the relocations applied. */
298 : 134 : Elf_Data *tdata = elf_rawdata (tscn, NULL);
299 [ + - ]: 134 : if (tdata == NULL)
300 : : return DWFL_E_LIBELF;
301 : :
302 : : /* Apply one relocation. Returns true for any invalid data. */
303 : 35966 : Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
304 : : int rtype, int symndx)
305 : : {
306 : : /* First see if this is a reloc we can handle.
307 : : If we are skipping it, don't bother resolving the symbol. */
308 : :
309 [ + - ]: 35966 : if (unlikely (rtype == 0))
310 : : /* In some odd situations, the linker can leave R_*_NONE relocs
311 : : behind. This is probably bogus ld -r behavior, but the only
312 : : cases it's known to appear in are harmless: DWARF data
313 : : referring to addresses in a section that has been discarded.
314 : : So we just pretend it's OK without further relocation. */
315 : : return DWFL_E_NOERROR;
316 : :
317 : 35966 : Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
318 [ + + ]: 35966 : if (unlikely (type == ELF_T_NUM))
319 : : return DWFL_E_BADRELTYPE;
320 : :
321 : : /* First, resolve the symbol to an absolute value. */
322 : : GElf_Addr value;
323 : :
324 [ + - ]: 32981 : if (symndx == STN_UNDEF)
325 : : /* When strip removes a section symbol referring to a
326 : : section moved into the debuginfo file, it replaces
327 : : that symbol index in relocs with STN_UNDEF. We
328 : : don't actually need the symbol, because those relocs
329 : : are always references relative to the nonallocated
330 : : debugging sections, which start at zero. */
331 : : value = 0;
332 : : else
333 : : {
334 : : GElf_Sym sym;
335 : : GElf_Word shndx;
336 : 32981 : Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
337 : : symndx, &sym, &shndx);
338 [ + - ]: 32981 : if (unlikely (error != DWFL_E_NOERROR))
339 : : return error;
340 : :
341 [ + + ]: 32981 : if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
342 : : {
343 : : /* Maybe we can figure it out anyway. */
344 : 9 : error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
345 [ + - ]: 9 : if (error != DWFL_E_NOERROR
346 [ + - ][ - + ]: 9 : && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
347 : : return error;
348 : : }
349 : :
350 : 32981 : value = sym.st_value;
351 : : }
352 : :
353 : : /* These are the types we can relocate. */
354 : : #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
355 : : DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
356 : : DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
357 : : size_t size;
358 [ - + + + : 32972 : switch (type)
+ - - ]
359 : : {
360 : : #define DO_TYPE(NAME, Name) \
361 : : case ELF_T_##NAME: \
362 : : size = sizeof (GElf_##Name); \
363 : : break
364 : 32972 : TYPES;
365 : : #undef DO_TYPE
366 : : default:
367 : : return DWFL_E_BADRELTYPE;
368 : : }
369 : :
370 [ + - ]: 32972 : if (offset + size > tdata->d_size)
371 : : return DWFL_E_BADRELOFF;
372 : :
373 : : #define DO_TYPE(NAME, Name) GElf_##Name Name;
374 : : union { TYPES; } tmpbuf;
375 : : #undef DO_TYPE
376 : 32972 : Elf_Data tmpdata =
377 : : {
378 : : .d_type = type,
379 : : .d_buf = &tmpbuf,
380 : : .d_size = size,
381 : : .d_version = EV_CURRENT,
382 : : };
383 : 65944 : Elf_Data rdata =
384 : : {
385 : : .d_type = type,
386 : 32972 : .d_buf = tdata->d_buf + offset,
387 : : .d_size = size,
388 : : .d_version = EV_CURRENT,
389 : : };
390 : :
391 : : /* XXX check for overflow? */
392 [ + + ]: 32972 : if (addend)
393 : : {
394 : : /* For the addend form, we have the value already. */
395 : 27979 : value += *addend;
396 [ - - + + : 27979 : switch (type)
+ + - ]
397 : : {
398 : : #define DO_TYPE(NAME, Name) \
399 : : case ELF_T_##NAME: \
400 : : tmpbuf.Name = value; \
401 : : break
402 : 27979 : TYPES;
403 : : #undef DO_TYPE
404 : : default:
405 : 0 : abort ();
406 : : }
407 : : }
408 : : else
409 : : {
410 : : /* Extract the original value and apply the reloc. */
411 : 4993 : Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
412 : 4993 : ehdr->e_ident[EI_DATA]);
413 [ + - ]: 4993 : if (d == NULL)
414 : : return DWFL_E_LIBELF;
415 [ - + ]: 4993 : assert (d == &tmpdata);
416 [ - - - + : 4993 : switch (type)
- - - ]
417 : : {
418 : : #define DO_TYPE(NAME, Name) \
419 : : case ELF_T_##NAME: \
420 : : tmpbuf.Name += (GElf_##Name) value; \
421 : : break
422 : 4993 : TYPES;
423 : : #undef DO_TYPE
424 : : default:
425 : 0 : abort ();
426 : : }
427 : : }
428 : :
429 : : /* Now convert the relocated datum back to the target
430 : : format. This will write into rdata.d_buf, which
431 : : points into the raw section data being relocated. */
432 : 32972 : Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
433 : 32972 : ehdr->e_ident[EI_DATA]);
434 [ + - ]: 32972 : if (s == NULL)
435 : : return DWFL_E_LIBELF;
436 [ - + ]: 35966 : assert (s == &rdata);
437 : :
438 : : /* We have applied this relocation! */
439 : : return DWFL_E_NOERROR;
440 : : }
441 : :
442 : : /* Fetch the relocation section and apply each reloc in it. */
443 : 134 : Elf_Data *reldata = elf_getdata (scn, NULL);
444 [ + - ]: 134 : if (reldata == NULL)
445 : : return DWFL_E_LIBELF;
446 : :
447 : 134 : Dwfl_Error result = DWFL_E_NOERROR;
448 : 134 : bool first_badreltype = true;
449 : 35966 : inline void check_badreltype (void)
450 : : {
451 [ + + ]: 35966 : if (first_badreltype)
452 : : {
453 : 134 : first_badreltype = false;
454 [ - + ]: 134 : if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
455 : : /* This might be because ebl_openbackend failed to find
456 : : any libebl_CPU.so library. Diagnose that clearly. */
457 : 0 : result = DWFL_E_UNKNOWN_MACHINE;
458 : : }
459 : 35966 : }
460 : :
461 : 134 : size_t nrels = shdr->sh_size / shdr->sh_entsize;
462 : 134 : size_t complete = 0;
463 [ + + ]: 134 : if (shdr->sh_type == SHT_REL)
464 [ + - ][ + + ]: 5504 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
465 : : {
466 : 5479 : GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
467 [ - + ]: 5479 : if (r == NULL)
468 : : return DWFL_E_LIBELF;
469 : 5479 : result = relocate (r->r_offset, NULL,
470 : : GELF_R_TYPE (r->r_info),
471 : 5479 : GELF_R_SYM (r->r_info));
472 : 5479 : check_badreltype ();
473 [ + + ]: 5479 : if (partial)
474 [ + + - ]: 4044 : switch (result)
475 : : {
476 : : case DWFL_E_NOERROR:
477 : : /* We applied the relocation. Elide it. */
478 : 3558 : memset (&rel_mem, 0, sizeof rel_mem);
479 : 3558 : gelf_update_rel (reldata, relidx, &rel_mem);
480 : 3558 : ++complete;
481 : 3558 : break;
482 : : case DWFL_E_BADRELTYPE:
483 : : case DWFL_E_RELUNDEF:
484 : : /* We couldn't handle this relocation. Skip it. */
485 : 486 : result = DWFL_E_NOERROR;
486 : 486 : break;
487 : : default:
488 : : break;
489 : : }
490 : : }
491 : : else
492 [ + - ][ + + ]: 30596 : for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
493 : : {
494 : 30487 : GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
495 : : &rela_mem);
496 [ - + ]: 30487 : if (r == NULL)
497 : : return DWFL_E_LIBELF;
498 : 30487 : result = relocate (r->r_offset, &r->r_addend,
499 : : GELF_R_TYPE (r->r_info),
500 : 30487 : GELF_R_SYM (r->r_info));
501 : 30487 : check_badreltype ();
502 [ + + ]: 30487 : if (partial)
503 [ + + - ]: 24314 : switch (result)
504 : : {
505 : : case DWFL_E_NOERROR:
506 : : /* We applied the relocation. Elide it. */
507 : 21806 : memset (&rela_mem, 0, sizeof rela_mem);
508 : 21806 : gelf_update_rela (reldata, relidx, &rela_mem);
509 : 21806 : ++complete;
510 : 21806 : break;
511 : : case DWFL_E_BADRELTYPE:
512 : : case DWFL_E_RELUNDEF:
513 : : /* We couldn't handle this relocation. Skip it. */
514 : 2508 : result = DWFL_E_NOERROR;
515 : 2508 : break;
516 : : default:
517 : : break;
518 : : }
519 : : }
520 : :
521 [ + - ]: 134 : if (likely (result == DWFL_E_NOERROR))
522 : : {
523 [ + + ]: 134 : if (!partial || complete == nrels)
524 : : /* Mark this relocation section as being empty now that we have
525 : : done its work. This affects unstrip -R, so e.g. it emits an
526 : : empty .rela.debug_info along with a .debug_info that has
527 : : already been fully relocated. */
528 : : nrels = 0;
529 [ + + ]: 25 : else if (complete != 0)
530 : : {
531 : : /* We handled some of the relocations but not all.
532 : : We've zeroed out the ones we processed.
533 : : Now remove them from the section. */
534 : :
535 : 16 : size_t next = 0;
536 [ + + ]: 16 : if (shdr->sh_type == SHT_REL)
537 [ + + ]: 782 : for (size_t relidx = 0; relidx < nrels; ++relidx)
538 : : {
539 : : GElf_Rel rel_mem;
540 : 778 : GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
541 [ + + ][ - + ]: 778 : if (r->r_info != 0 || r->r_offset != 0)
542 : : {
543 [ + + ]: 486 : if (next != relidx)
544 : 470 : gelf_update_rel (reldata, next, r);
545 : 486 : ++next;
546 : : }
547 : : }
548 : : else
549 [ + + ]: 3068 : for (size_t relidx = 0; relidx < nrels; ++relidx)
550 : : {
551 : : GElf_Rela rela_mem;
552 : 3056 : GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
553 [ + + ][ + - ]: 3056 : if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
[ - + ]
554 : : {
555 [ + + ]: 2465 : if (next != relidx)
556 : 2440 : gelf_update_rela (reldata, next, r);
557 : 2465 : ++next;
558 : : }
559 : : }
560 : 16 : nrels = next;
561 : : }
562 : :
563 : 134 : shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
564 : 134 : gelf_update_shdr (scn, shdr);
565 : : }
566 : :
567 : 150 : return result;
568 : : }
569 : :
570 : : Dwfl_Error
571 : : internal_function
572 : 37 : __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
573 : : {
574 [ - + ]: 37 : assert (mod->e_type == ET_REL);
575 : :
576 : : GElf_Ehdr ehdr_mem;
577 : 37 : const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
578 [ + - ]: 37 : if (ehdr == NULL)
579 : : return DWFL_E_LIBELF;
580 : :
581 : : size_t d_shstrndx;
582 [ + - ]: 37 : if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
583 : : return DWFL_E_LIBELF;
584 : :
585 : 37 : RELOC_SYMTAB_CACHE (reloc_symtab);
586 : :
587 : : /* Look at each section in the debuginfo file, and process the
588 : : relocation sections for debugging sections. */
589 : 37 : Dwfl_Error result = DWFL_E_NOERROR;
590 : 37 : Elf_Scn *scn = NULL;
591 [ + - ]: 803 : while (result == DWFL_E_NOERROR
592 [ + + ]: 803 : && (scn = elf_nextscn (debugfile, scn)) != NULL)
593 : : {
594 : : GElf_Shdr shdr_mem;
595 : 766 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
596 : :
597 [ + + ]: 766 : if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
598 [ + + ]: 154 : && shdr->sh_size != 0)
599 : : {
600 : : /* It's a relocation section. */
601 : :
602 : 148 : Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
603 [ + - ]: 148 : if (unlikely (tscn == NULL))
604 : : result = DWFL_E_LIBELF;
605 : : else
606 : 766 : result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
607 : : &reloc_symtab, scn, shdr, tscn,
608 : 148 : debug, !debug);
609 : : }
610 : : }
611 : :
612 : : return result;
613 : : }
614 : :
615 : : Dwfl_Error
616 : : internal_function
617 : 2 : __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
618 : : Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
619 : : {
620 : : GElf_Ehdr ehdr_mem;
621 : : GElf_Shdr shdr_mem;
622 : :
623 : 2 : RELOC_SYMTAB_CACHE (reloc_symtab);
624 : :
625 : : size_t shstrndx;
626 [ + - ]: 2 : if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
627 : : return DWFL_E_LIBELF;
628 : :
629 [ + - ]: 4 : return (__libdwfl_module_getebl (mod)
630 : 2 : ?: relocate_section (mod, relocated,
631 : 2 : gelf_getehdr (relocated, &ehdr_mem), shstrndx,
632 : : &reloc_symtab,
633 : : relocscn, gelf_getshdr (relocscn, &shdr_mem),
634 : : tscn, false, partial));
635 : 635736 : }
|