1 /* Relocate debug information.
2 Copyright (C) 2005, 2006, 2007, 2008 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 /* Apply the adjustment. */
99 *value += refshdr->sh_addr;
100 return DWFL_E_NOERROR;
104 /* Cache used by relocate_getsym. */
105 struct reloc_symtab_cache
109 Elf_Data *symxndxdata;
110 Elf_Data *symstrdata;
114 #define RELOC_SYMTAB_CACHE(cache) \
115 struct reloc_symtab_cache cache = \
116 { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
118 /* This is just doing dwfl_module_getsym, except that we must always use
119 the symbol table in RELOCATED itself when it has one, not MOD->symfile. */
121 relocate_getsym (Dwfl_Module *mod,
122 Elf *relocated, struct reloc_symtab_cache *cache,
123 int symndx, GElf_Sym *sym, GElf_Word *shndx)
125 if (cache->symdata == NULL)
127 if (mod->symfile == NULL || mod->symfile->elf != relocated)
129 /* We have to look up the symbol table in the file we are
130 relocating, if it has its own. These reloc sections refer to
131 the symbol table in this file, and a symbol table in the main
132 file might not match. However, some tools did produce ET_REL
133 .debug files with relocs but no symtab of their own. */
135 while ((scn = elf_nextscn (relocated, scn)) != NULL)
137 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
139 switch (shdr->sh_type)
144 cache->symelf = relocated;
145 cache->symdata = elf_getdata (scn, NULL);
146 cache->strtabndx = shdr->sh_link;
147 if (unlikely (cache->symdata == NULL))
148 return DWFL_E_LIBELF;
150 case SHT_SYMTAB_SHNDX:
151 cache->symxndxdata = elf_getdata (scn, NULL);
152 if (unlikely (cache->symxndxdata == NULL))
153 return DWFL_E_LIBELF;
156 if (cache->symdata != NULL && cache->symxndxdata != NULL)
160 if (cache->symdata == NULL)
162 /* We might not have looked for a symbol table file yet,
163 when coming from __libdwfl_relocate_section. */
164 if (unlikely (mod->symfile == NULL)
165 && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
166 return dwfl_errno ();
168 /* The symbol table we have already cached is the one from
169 the file being relocated, so it's what we need. Or else
170 this is an ET_REL .debug file with no .symtab of its own;
171 the symbols refer to the section indices in the main file. */
172 cache->symelf = mod->symfile->elf;
173 cache->symdata = mod->symdata;
174 cache->symxndxdata = mod->symxndxdata;
175 cache->symstrdata = mod->symstrdata;
179 if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
180 symndx, sym, shndx) == NULL))
181 return DWFL_E_LIBELF;
183 if (sym->st_shndx != SHN_XINDEX)
184 *shndx = sym->st_shndx;
191 return DWFL_E_NOERROR;
194 return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
195 *shndx, &sym->st_value);
198 /* Handle an undefined symbol. We really only support ET_REL for Linux
199 kernel modules, and offline archives. The behavior of the Linux module
200 loader is very simple and easy to mimic. It only matches magically
201 exported symbols, and we match any defined symbols. But we get the same
202 answer except when the module's symbols are undefined and would prevent
203 it from being loaded. */
205 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
206 GElf_Sym *sym, GElf_Word shndx)
208 /* First we need its name. */
209 if (sym->st_name != 0)
211 if (symtab->symstrdata == NULL)
213 /* Cache the strtab for this symtab. */
214 assert (referer->symfile == NULL
215 || referer->symfile->elf != symtab->symelf);
216 symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
219 if (unlikely (symtab->symstrdata == NULL))
220 return DWFL_E_LIBELF;
222 if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
223 return DWFL_E_BADSTROFF;
225 const char *name = symtab->symstrdata->d_buf;
226 name += sym->st_name;
228 for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
231 /* Get this module's symtab.
232 If we got a fresh error reading the table, report it.
233 If we just have no symbols in this module, no harm done. */
234 if (m->symdata == NULL
235 && m->symerr == DWFL_E_NOERROR
236 && INTUSE(dwfl_module_getsymtab) (m) < 0
237 && m->symerr != DWFL_E_NO_SYMTAB)
240 for (size_t ndx = 1; ndx < m->syments; ++ndx)
242 sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
244 if (unlikely (sym == NULL))
245 return DWFL_E_LIBELF;
246 if (sym->st_shndx != SHN_XINDEX)
247 shndx = sym->st_shndx;
249 /* We are looking for a defined global symbol with a name. */
250 if (shndx == SHN_UNDEF || shndx == SHN_COMMON
251 || GELF_ST_BIND (sym->st_info) == STB_LOCAL
252 || sym->st_name == 0)
255 /* Get this candidate symbol's name. */
256 if (unlikely (sym->st_name >= m->symstrdata->d_size))
257 return DWFL_E_BADSTROFF;
258 const char *n = m->symstrdata->d_buf;
261 /* Does the name match? */
262 if (strcmp (name, n))
266 if (shndx == SHN_ABS)
267 return DWFL_E_NOERROR;
269 /* In an ET_REL file, the symbol table values are relative
270 to the section, not to the module's load base. */
271 size_t symshstrndx = SHN_UNDEF;
272 return __libdwfl_relocate_value (m, m->symfile->elf,
274 shndx, &sym->st_value);
279 return DWFL_E_RELUNDEF;
283 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
284 size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
285 Elf_Scn *scn, GElf_Shdr *shdr,
286 Elf_Scn *tscn, bool debugscn, bool partial)
288 /* First, fetch the name of the section these relocations apply to. */
290 GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
291 const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
293 return DWFL_E_LIBELF;
295 if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
296 /* This relocation section is not for a debugging section.
297 Nothing to do here. */
298 return DWFL_E_NOERROR;
300 /* Fetch the section data that needs the relocations applied. */
301 Elf_Data *tdata = elf_rawdata (tscn, NULL);
303 return DWFL_E_LIBELF;
305 /* Apply one relocation. Returns true for any invalid data. */
306 Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
307 int rtype, int symndx)
309 /* First see if this is a reloc we can handle.
310 If we are skipping it, don't bother resolving the symbol. */
311 Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
312 if (unlikely (type == ELF_T_NUM))
313 return DWFL_E_BADRELTYPE;
315 /* First, resolve the symbol to an absolute value. */
318 if (symndx == STN_UNDEF)
319 /* When strip removes a section symbol referring to a
320 section moved into the debuginfo file, it replaces
321 that symbol index in relocs with STN_UNDEF. We
322 don't actually need the symbol, because those relocs
323 are always references relative to the nonallocated
324 debugging sections, which start at zero. */
330 Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
331 symndx, &sym, &shndx);
332 if (unlikely (error != DWFL_E_NOERROR))
335 if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
337 /* Maybe we can figure it out anyway. */
338 error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
339 if (error != DWFL_E_NOERROR)
343 value = sym.st_value;
346 /* These are the types we can relocate. */
347 #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
348 DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
349 DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
353 #define DO_TYPE(NAME, Name) \
355 size = sizeof (GElf_##Name); \
360 return DWFL_E_BADRELTYPE;
363 if (offset + size > tdata->d_size)
364 return DWFL_E_BADRELOFF;
366 #define DO_TYPE(NAME, Name) GElf_##Name Name;
367 union { TYPES; } tmpbuf;
374 .d_version = EV_CURRENT,
379 .d_buf = tdata->d_buf + offset,
381 .d_version = EV_CURRENT,
384 /* XXX check for overflow? */
387 /* For the addend form, we have the value already. */
391 #define DO_TYPE(NAME, Name) \
393 tmpbuf.Name = value; \
403 /* Extract the original value and apply the reloc. */
404 Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
405 ehdr->e_ident[EI_DATA]);
407 return DWFL_E_LIBELF;
408 assert (d == &tmpdata);
411 #define DO_TYPE(NAME, Name) \
413 tmpbuf.Name += (GElf_##Name) value; \
422 /* Now convert the relocated datum back to the target
423 format. This will write into rdata.d_buf, which
424 points into the raw section data being relocated. */
425 Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
426 ehdr->e_ident[EI_DATA]);
428 return DWFL_E_LIBELF;
429 assert (s == &rdata);
431 /* We have applied this relocation! */
432 return DWFL_E_NOERROR;
435 /* Fetch the relocation section and apply each reloc in it. */
436 Elf_Data *reldata = elf_getdata (scn, NULL);
438 return DWFL_E_LIBELF;
440 Dwfl_Error result = DWFL_E_NOERROR;
441 bool first_badreltype = true;
442 inline void check_badreltype (void)
444 if (first_badreltype)
446 first_badreltype = false;
447 if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
448 /* This might be because ebl_openbackend failed to find
449 any libebl_CPU.so library. Diagnose that clearly. */
450 result = DWFL_E_UNKNOWN_MACHINE;
454 size_t nrels = shdr->sh_size / shdr->sh_entsize;
456 if (shdr->sh_type == SHT_REL)
457 for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
459 GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
461 return DWFL_E_LIBELF;
462 result = relocate (r->r_offset, NULL,
463 GELF_R_TYPE (r->r_info),
464 GELF_R_SYM (r->r_info));
470 /* We applied the relocation. Elide it. */
471 memset (&rel_mem, 0, sizeof rel_mem);
472 gelf_update_rel (reldata, relidx, &rel_mem);
475 case DWFL_E_BADRELTYPE:
476 case DWFL_E_RELUNDEF:
477 /* We couldn't handle this relocation. Skip it. */
478 result = DWFL_E_NOERROR;
485 for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
487 GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
490 return DWFL_E_LIBELF;
491 result = relocate (r->r_offset, &r->r_addend,
492 GELF_R_TYPE (r->r_info),
493 GELF_R_SYM (r->r_info));
499 /* We applied the relocation. Elide it. */
500 memset (&rela_mem, 0, sizeof rela_mem);
501 gelf_update_rela (reldata, relidx, &rela_mem);
504 case DWFL_E_BADRELTYPE:
505 case DWFL_E_RELUNDEF:
506 /* We couldn't handle this relocation. Skip it. */
507 result = DWFL_E_NOERROR;
514 if (likely (result == DWFL_E_NOERROR))
516 if (!partial || complete == nrels)
517 /* Mark this relocation section as being empty now that we have
518 done its work. This affects unstrip -R, so e.g. it emits an
519 empty .rela.debug_info along with a .debug_info that has
520 already been fully relocated. */
522 else if (complete != 0)
524 /* We handled some of the relocations but not all.
525 We've zeroed out the ones we processed.
526 Now remove them from the section. */
529 if (shdr->sh_type == SHT_REL)
530 for (size_t relidx = 0; relidx < nrels; ++relidx)
533 GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
534 if (r->r_info != 0 || r->r_offset != 0)
537 gelf_update_rel (reldata, next, r);
542 for (size_t relidx = 0; relidx < nrels; ++relidx)
545 GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
546 if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
549 gelf_update_rela (reldata, next, r);
556 shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
557 gelf_update_shdr (scn, shdr);
565 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
567 assert (mod->e_type == ET_REL);
570 const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
572 return DWFL_E_LIBELF;
575 if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
576 return DWFL_E_LIBELF;
578 RELOC_SYMTAB_CACHE (reloc_symtab);
580 /* Look at each section in the debuginfo file, and process the
581 relocation sections for debugging sections. */
582 Dwfl_Error result = DWFL_E_NOERROR;
584 while (result == DWFL_E_NOERROR
585 && (scn = elf_nextscn (debugfile, scn)) != NULL)
588 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
590 if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
591 && shdr->sh_size != 0)
593 /* It's a relocation section. */
595 Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
596 if (unlikely (tscn == NULL))
597 result = DWFL_E_LIBELF;
599 result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
600 &reloc_symtab, scn, shdr, tscn,
610 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
611 Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
616 RELOC_SYMTAB_CACHE (reloc_symtab);
619 if (elf_getshstrndx (relocated, &shstrndx) < 0)
620 return DWFL_E_LIBELF;
622 return (__libdwfl_module_getebl (mod)
623 ?: relocate_section (mod, relocated,
624 gelf_getehdr (relocated, &ehdr_mem), shstrndx,
626 relocscn, gelf_getshdr (relocscn, &shdr_mem),
627 tscn, false, partial));