1 /* Relocate debug information.
2 Copyright (C) 2005 Red Hat, Inc.
4 This program is Open Source software; you can redistribute it and/or
5 modify it under the terms of the Open Software License version 1.0 as
6 published by the Open Source Initiative.
8 You should have received a copy of the Open Software License along
9 with this program; if not, you may obtain a copy of the Open Software
10 License version 1.0 from http://www.opensource.org/licenses/osl.php or
11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12 3001 King Ranch Road, Ukiah, CA 95482. */
16 typedef uint8_t GElf_Byte;
18 /* Adjust *VALUE to add the load address of the SHNDX section.
19 We update the section header in place to cache the result. */
23 __libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx,
24 Elf32_Word shndx, GElf_Addr *value)
26 Elf_Scn *refscn = elf_getscn (mod->symfile->elf, shndx);
27 GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
31 if ((refshdr->sh_flags & SHF_ALLOC) && refshdr->sh_addr == 0)
33 /* This is a loaded section. Find its actual
34 address and update the section header. */
35 const char *name = elf_strptr (mod->symfile->elf, symshstrndx,
40 if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), name,
44 if (refshdr->sh_addr == 0)
45 /* The callback resolved this to zero, indicating it wasn't
46 really loaded but we don't really care. Mark it so we
47 don't check it again for the next relocation. */
48 refshdr->sh_flags &= ~SHF_ALLOC;
50 /* Update the in-core file's section header to show the final
51 load address (or unloadedness). This serves as a cache,
52 so we won't get here again for the same section. */
53 if (! gelf_update_shdr (refscn, refshdr))
57 /* Apply the adjustment. */
58 *value += refshdr->sh_addr;
59 return DWFL_E_NOERROR;
64 __libdwfl_relocate (Dwfl_Module *mod)
69 const GElf_Ehdr *ehdr = gelf_getehdr (mod->debug.elf, &ehdr_mem);
73 size_t symshstrndx, d_shstrndx;
74 if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) < 0)
76 if (mod->symfile == &mod->debug)
77 d_shstrndx = symshstrndx;
78 else if (elf_getshstrndx (mod->debug.elf, &d_shstrndx) < 0)
81 /* Look at each section in the debuginfo file, and process the
82 relocation sections for debugging sections. */
83 Dwfl_Error result = DWFL_E_NO_DWARF;
85 while ((scn = elf_nextscn (mod->debug.elf, scn)) != NULL)
88 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
90 if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
92 /* It's a relocation section. First, fetch the name of the
93 section these relocations apply to. */
95 Elf_Scn *tscn = elf_getscn (mod->debug.elf, shdr->sh_info);
100 GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
101 const char *tname = elf_strptr (mod->debug.elf, d_shstrndx,
104 return DWFL_E_LIBELF;
106 if (! ebl_debugscn_p (mod->ebl, tname))
107 /* This relocation section is not for a debugging section.
108 Nothing to do here. */
111 /* Fetch the section data that needs the relocations applied. */
112 Elf_Data *tdata = elf_rawdata (tscn, NULL);
114 return DWFL_E_LIBELF;
116 /* Apply one relocation. Returns true for any invalid data. */
117 Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
118 int rtype, int symndx)
120 /* First, resolve the symbol to an absolute value. */
122 inline Dwfl_Error adjust (GElf_Word shndx)
124 return __libdwfl_relocate_value (mod, symshstrndx,
128 if (symndx == STN_UNDEF)
129 /* When strip removes a section symbol referring to a
130 section moved into the debuginfo file, it replaces
131 that symbol index in relocs with STN_UNDEF. We
132 don't actually need the symbol, because those relocs
133 are always references relative to the nonallocated
134 debugging sections, which start at zero. */
140 GElf_Sym *sym = gelf_getsymshndx (mod->symdata,
145 return DWFL_E_LIBELF;
147 value = sym->st_value;
148 if (sym->st_shndx != SHN_XINDEX)
149 shndx = sym->st_shndx;
157 return DWFL_E_RELUNDEF;
161 Dwfl_Error error = adjust (shndx);
162 if (error != DWFL_E_NOERROR)
169 /* These are the types we can relocate. */
170 #define TYPES DO_TYPE (BYTE, Byte) DO_TYPE (HALF, Half) \
171 DO_TYPE (WORD, Word) DO_TYPE (SWORD, Sword) \
172 DO_TYPE (XWORD, Xword) DO_TYPE (SXWORD, Sxword)
174 Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
177 #define DO_TYPE(NAME, Name) \
179 size = sizeof (GElf_##Name); \
184 return DWFL_E_BADRELTYPE;
187 if (offset + size >= tdata->d_size)
188 return DWFL_E_BADRELOFF;
190 #define DO_TYPE(NAME, Name) GElf_##Name Name;
191 union { TYPES } tmpbuf;
198 .d_version = EV_CURRENT,
203 .d_buf = tdata->d_buf + offset,
205 .d_version = EV_CURRENT,
208 /* XXX check for overflow? */
211 /* For the addend form, we have the value already. */
215 #define DO_TYPE(NAME, Name) \
217 tmpbuf.Name = value; \
227 /* Extract the original value and apply the reloc. */
228 Elf_Data *d = gelf_xlatetom (mod->main.elf, &tmpdata, &rdata,
229 ehdr->e_ident[EI_DATA]);
231 return DWFL_E_LIBELF;
232 assert (d == &tmpdata);
235 #define DO_TYPE(NAME, Name) \
237 tmpbuf.Name += (GElf_##Name) value; \
246 /* Now convert the relocated datum back to the target
247 format. This will write into rdata.d_buf, which
248 points into the raw section data being relocated. */
249 Elf_Data *s = gelf_xlatetof (mod->main.elf, &rdata, &tmpdata,
250 ehdr->e_ident[EI_DATA]);
252 return DWFL_E_LIBELF;
253 assert (s == &rdata);
255 /* We have applied this relocation! */
256 return DWFL_E_NOERROR;
259 /* Fetch the relocation section and apply each reloc in it. */
260 Elf_Data *reldata = elf_getdata (scn, NULL);
262 return DWFL_E_LIBELF;
264 result = DWFL_E_NOERROR;
265 size_t nrels = shdr->sh_size / shdr->sh_entsize;
266 if (shdr->sh_type == SHT_REL)
267 for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
269 GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
271 return DWFL_E_LIBELF;
272 result = relocate (r->r_offset, NULL,
273 GELF_R_TYPE (r->r_info),
274 GELF_R_SYM (r->r_info));
277 for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
279 GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
282 return DWFL_E_LIBELF;
283 result = relocate (r->r_offset, &r->r_addend,
284 GELF_R_TYPE (r->r_info),
285 GELF_R_SYM (r->r_info));
287 if (result != DWFL_E_NOERROR)