1 /* Relocate debug information.
2 Copyright (C) 2005-2009 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
5 Red Hat elfutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
9 Red Hat elfutils is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with Red Hat elfutils; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18 In addition, as a special exception, Red Hat, Inc. gives You the
19 additional right to link the code of Red Hat elfutils with code licensed
20 under any Open Source Initiative certified open source license
21 (http://www.opensource.org/licenses/index.php) which requires the
22 distribution of source code with any binary distribution and to
23 distribute linked combinations of the two. Non-GPL Code permitted under
24 this exception must only link to the code of Red Hat elfutils through
25 those well defined interfaces identified in the file named EXCEPTION
26 found in the source code files (the "Approved Interfaces"). The files
27 of Non-GPL Code may instantiate templates or use macros or inline
28 functions from the Approved Interfaces without causing the resulting
29 work to be covered by the GNU General Public License. Only Red Hat,
30 Inc. may make changes or additions to the list of Approved Interfaces.
31 Red Hat's grant of this exception is conditioned upon your not adding
32 any new exceptions. If you wish to add a new Approved Interface or
33 exception, please contact Red Hat. You must obey the GNU General Public
34 License in all respects for all of the Red Hat elfutils code and other
35 code used in conjunction with Red Hat elfutils except the Non-GPL Code
36 covered by this exception. If you modify this file, you may extend this
37 exception to your version of the file, but you are not obligated to do
38 so. If you do not wish to provide this exception without modification,
39 you must delete this exception statement from your version and license
40 this file solely under the GPL without exception.
42 Red Hat elfutils is an included package of the Open Invention Network.
43 An included package of the Open Invention Network is a package for which
44 Open Invention Network licensees cross-license their patents. No patent
45 license is granted, either expressly or impliedly, by designation as an
46 included package. Should you wish to participate in the Open Invention
47 Network licensing program, please visit www.openinventionnetwork.com
48 <http://www.openinventionnetwork.com>. */
52 typedef uint8_t GElf_Byte;
54 /* Adjust *VALUE to add the load address of the SHNDX section.
55 We update the section header in place to cache the result. */
59 __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
60 Elf32_Word shndx, GElf_Addr *value)
62 Elf_Scn *refscn = elf_getscn (elf, shndx);
63 GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
67 if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
69 /* This is a loaded section. Find its actual
70 address and update the section header. */
72 if (*shstrndx == SHN_UNDEF
73 && unlikely (elf_getshstrndx (elf, shstrndx) < 0))
76 const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
77 if (unlikely (name == NULL))
80 if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
85 if (refshdr->sh_addr == (Dwarf_Addr) -1l)
86 /* The callback indicated this section wasn't really loaded but we
88 refshdr->sh_addr = 0; /* Make no adjustment below. */
90 /* Update the in-core file's section header to show the final
91 load address (or unloadedness). This serves as a cache,
92 so we won't get here again for the same section. */
93 if (likely (refshdr->sh_addr != 0)
94 && unlikely (! gelf_update_shdr (refscn, refshdr)))
98 if (refshdr->sh_flags & SHF_ALLOC)
99 /* Apply the adjustment. */
100 *value += refshdr->sh_addr + mod->main.bias;
102 return DWFL_E_NOERROR;
106 /* Cache used by relocate_getsym. */
107 struct reloc_symtab_cache
111 Elf_Data *symxndxdata;
112 Elf_Data *symstrdata;
116 #define RELOC_SYMTAB_CACHE(cache) \
117 struct reloc_symtab_cache cache = \
118 { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
120 /* This is just doing dwfl_module_getsym, except that we must always use
121 the symbol table in RELOCATED itself when it has one, not MOD->symfile. */
123 relocate_getsym (Dwfl_Module *mod,
124 Elf *relocated, struct reloc_symtab_cache *cache,
125 int symndx, GElf_Sym *sym, GElf_Word *shndx)
127 if (cache->symdata == NULL)
129 if (mod->symfile == NULL || mod->symfile->elf != relocated)
131 /* We have to look up the symbol table in the file we are
132 relocating, if it has its own. These reloc sections refer to
133 the symbol table in this file, and a symbol table in the main
134 file might not match. However, some tools did produce ET_REL
135 .debug files with relocs but no symtab of their own. */
137 while ((scn = elf_nextscn (relocated, scn)) != NULL)
139 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
141 switch (shdr->sh_type)
146 cache->symelf = relocated;
147 cache->symdata = elf_getdata (scn, NULL);
148 cache->strtabndx = shdr->sh_link;
149 if (unlikely (cache->symdata == NULL))
150 return DWFL_E_LIBELF;
152 case SHT_SYMTAB_SHNDX:
153 cache->symxndxdata = elf_getdata (scn, NULL);
154 if (unlikely (cache->symxndxdata == NULL))
155 return DWFL_E_LIBELF;
158 if (cache->symdata != NULL && cache->symxndxdata != NULL)
162 if (cache->symdata == NULL)
164 /* We might not have looked for a symbol table file yet,
165 when coming from __libdwfl_relocate_section. */
166 if (unlikely (mod->symfile == NULL)
167 && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
168 return dwfl_errno ();
170 /* The symbol table we have already cached is the one from
171 the file being relocated, so it's what we need. Or else
172 this is an ET_REL .debug file with no .symtab of its own;
173 the symbols refer to the section indices in the main file. */
174 cache->symelf = mod->symfile->elf;
175 cache->symdata = mod->symdata;
176 cache->symxndxdata = mod->symxndxdata;
177 cache->symstrdata = mod->symstrdata;
181 if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
182 symndx, sym, shndx) == NULL))
183 return DWFL_E_LIBELF;
185 if (sym->st_shndx != SHN_XINDEX)
186 *shndx = sym->st_shndx;
188 switch (sym->st_shndx)
193 return DWFL_E_NOERROR;
196 return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
197 *shndx, &sym->st_value);
200 /* Handle an undefined symbol. We really only support ET_REL for Linux
201 kernel modules, and offline archives. The behavior of the Linux module
202 loader is very simple and easy to mimic. It only matches magically
203 exported symbols, and we match any defined symbols. But we get the same
204 answer except when the module's symbols are undefined and would prevent
205 it from being loaded. */
207 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
208 GElf_Sym *sym, GElf_Word shndx)
210 /* First we need its name. */
211 if (sym->st_name != 0)
213 if (symtab->symstrdata == NULL)
215 /* Cache the strtab for this symtab. */
216 assert (referer->symfile == NULL
217 || referer->symfile->elf != symtab->symelf);
218 symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
221 if (unlikely (symtab->symstrdata == NULL))
222 return DWFL_E_LIBELF;
224 if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
225 return DWFL_E_BADSTROFF;
227 const char *name = symtab->symstrdata->d_buf;
228 name += sym->st_name;
230 for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
233 /* Get this module's symtab.
234 If we got a fresh error reading the table, report it.
235 If we just have no symbols in this module, no harm done. */
236 if (m->symdata == NULL
237 && m->symerr == DWFL_E_NOERROR
238 && INTUSE(dwfl_module_getsymtab) (m) < 0
239 && m->symerr != DWFL_E_NO_SYMTAB)
242 for (size_t ndx = 1; ndx < m->syments; ++ndx)
244 sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
246 if (unlikely (sym == NULL))
247 return DWFL_E_LIBELF;
248 if (sym->st_shndx != SHN_XINDEX)
249 shndx = sym->st_shndx;
251 /* We are looking for a defined global symbol with a name. */
252 if (shndx == SHN_UNDEF || shndx == SHN_COMMON
253 || GELF_ST_BIND (sym->st_info) == STB_LOCAL
254 || sym->st_name == 0)
257 /* Get this candidate symbol's name. */
258 if (unlikely (sym->st_name >= m->symstrdata->d_size))
259 return DWFL_E_BADSTROFF;
260 const char *n = m->symstrdata->d_buf;
263 /* Does the name match? */
264 if (strcmp (name, n))
268 if (shndx == SHN_ABS)
269 return DWFL_E_NOERROR;
271 /* In an ET_REL file, the symbol table values are relative
272 to the section, not to the module's load base. */
273 size_t symshstrndx = SHN_UNDEF;
274 return __libdwfl_relocate_value (m, m->symfile->elf,
276 shndx, &sym->st_value);
281 return DWFL_E_RELUNDEF;
285 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
286 size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
287 Elf_Scn *scn, GElf_Shdr *shdr,
288 Elf_Scn *tscn, bool debugscn, bool partial)
290 /* First, fetch the name of the section these relocations apply to. */
292 GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
293 const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
295 return DWFL_E_LIBELF;
297 if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
298 /* This relocation section is not for a debugging section.
299 Nothing to do here. */
300 return DWFL_E_NOERROR;
302 /* Fetch the section data that needs the relocations applied. */
303 Elf_Data *tdata = elf_rawdata (tscn, NULL);
305 return DWFL_E_LIBELF;
307 /* Apply one relocation. Returns true for any invalid data. */
308 Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
309 int rtype, int symndx)
311 /* First see if this is a reloc we can handle.
312 If we are skipping it, don't bother resolving the symbol. */
313 Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
314 if (unlikely (type == ELF_T_NUM))
315 return DWFL_E_BADRELTYPE;
317 /* First, resolve the symbol to an absolute value. */
320 if (symndx == STN_UNDEF)
321 /* When strip removes a section symbol referring to a
322 section moved into the debuginfo file, it replaces
323 that symbol index in relocs with STN_UNDEF. We
324 don't actually need the symbol, because those relocs
325 are always references relative to the nonallocated
326 debugging sections, which start at zero. */
332 Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
333 symndx, &sym, &shndx);
334 if (unlikely (error != DWFL_E_NOERROR))
337 if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
339 /* Maybe we can figure it out anyway. */
340 error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
341 if (error != DWFL_E_NOERROR)
345 value = sym.st_value;
348 /* These are the types we can relocate. */
349 #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
350 DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
351 DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
355 #define DO_TYPE(NAME, Name) \
357 size = sizeof (GElf_##Name); \
362 return DWFL_E_BADRELTYPE;
365 if (offset + size > tdata->d_size)
366 return DWFL_E_BADRELOFF;
368 #define DO_TYPE(NAME, Name) GElf_##Name Name;
369 union { TYPES; } tmpbuf;
376 .d_version = EV_CURRENT,
381 .d_buf = tdata->d_buf + offset,
383 .d_version = EV_CURRENT,
386 /* XXX check for overflow? */
389 /* For the addend form, we have the value already. */
393 #define DO_TYPE(NAME, Name) \
395 tmpbuf.Name = value; \
405 /* Extract the original value and apply the reloc. */
406 Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
407 ehdr->e_ident[EI_DATA]);
409 return DWFL_E_LIBELF;
410 assert (d == &tmpdata);
413 #define DO_TYPE(NAME, Name) \
415 tmpbuf.Name += (GElf_##Name) value; \
424 /* Now convert the relocated datum back to the target
425 format. This will write into rdata.d_buf, which
426 points into the raw section data being relocated. */
427 Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
428 ehdr->e_ident[EI_DATA]);
430 return DWFL_E_LIBELF;
431 assert (s == &rdata);
433 /* We have applied this relocation! */
434 return DWFL_E_NOERROR;
437 /* Fetch the relocation section and apply each reloc in it. */
438 Elf_Data *reldata = elf_getdata (scn, NULL);
440 return DWFL_E_LIBELF;
442 Dwfl_Error result = DWFL_E_NOERROR;
443 bool first_badreltype = true;
444 inline void check_badreltype (void)
446 if (first_badreltype)
448 first_badreltype = false;
449 if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
450 /* This might be because ebl_openbackend failed to find
451 any libebl_CPU.so library. Diagnose that clearly. */
452 result = DWFL_E_UNKNOWN_MACHINE;
456 size_t nrels = shdr->sh_size / shdr->sh_entsize;
458 if (shdr->sh_type == SHT_REL)
459 for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
461 GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
463 return DWFL_E_LIBELF;
464 result = relocate (r->r_offset, NULL,
465 GELF_R_TYPE (r->r_info),
466 GELF_R_SYM (r->r_info));
472 /* We applied the relocation. Elide it. */
473 memset (&rel_mem, 0, sizeof rel_mem);
474 gelf_update_rel (reldata, relidx, &rel_mem);
477 case DWFL_E_BADRELTYPE:
478 case DWFL_E_RELUNDEF:
479 /* We couldn't handle this relocation. Skip it. */
480 result = DWFL_E_NOERROR;
487 for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
489 GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
492 return DWFL_E_LIBELF;
493 result = relocate (r->r_offset, &r->r_addend,
494 GELF_R_TYPE (r->r_info),
495 GELF_R_SYM (r->r_info));
501 /* We applied the relocation. Elide it. */
502 memset (&rela_mem, 0, sizeof rela_mem);
503 gelf_update_rela (reldata, relidx, &rela_mem);
506 case DWFL_E_BADRELTYPE:
507 case DWFL_E_RELUNDEF:
508 /* We couldn't handle this relocation. Skip it. */
509 result = DWFL_E_NOERROR;
516 if (likely (result == DWFL_E_NOERROR))
518 if (!partial || complete == nrels)
519 /* Mark this relocation section as being empty now that we have
520 done its work. This affects unstrip -R, so e.g. it emits an
521 empty .rela.debug_info along with a .debug_info that has
522 already been fully relocated. */
524 else if (complete != 0)
526 /* We handled some of the relocations but not all.
527 We've zeroed out the ones we processed.
528 Now remove them from the section. */
531 if (shdr->sh_type == SHT_REL)
532 for (size_t relidx = 0; relidx < nrels; ++relidx)
535 GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
536 if (r->r_info != 0 || r->r_offset != 0)
539 gelf_update_rel (reldata, next, r);
544 for (size_t relidx = 0; relidx < nrels; ++relidx)
547 GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
548 if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
551 gelf_update_rela (reldata, next, r);
558 shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
559 gelf_update_shdr (scn, shdr);
567 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
569 assert (mod->e_type == ET_REL);
572 const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
574 return DWFL_E_LIBELF;
577 if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
578 return DWFL_E_LIBELF;
580 RELOC_SYMTAB_CACHE (reloc_symtab);
582 /* Look at each section in the debuginfo file, and process the
583 relocation sections for debugging sections. */
584 Dwfl_Error result = DWFL_E_NOERROR;
586 while (result == DWFL_E_NOERROR
587 && (scn = elf_nextscn (debugfile, scn)) != NULL)
590 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
592 if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
593 && shdr->sh_size != 0)
595 /* It's a relocation section. */
597 Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
598 if (unlikely (tscn == NULL))
599 result = DWFL_E_LIBELF;
601 result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
602 &reloc_symtab, scn, shdr, tscn,
612 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
613 Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
618 RELOC_SYMTAB_CACHE (reloc_symtab);
621 if (elf_getshstrndx (relocated, &shstrndx) < 0)
622 return DWFL_E_LIBELF;
624 return (__libdwfl_module_getebl (mod)
625 ?: relocate_section (mod, relocated,
626 gelf_getehdr (relocated, &ehdr_mem), shstrndx,
628 relocscn, gelf_getshdr (relocscn, &shdr_mem),
629 tscn, false, partial));