1 /* Recover relocatibility for addresses computed from debug information.
2 Copyright (C) 2005-2010, 2013 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
31 struct dwfl_relocation
54 compare_secrefs (const void *a, const void *b)
56 struct secref *const *p1 = a;
57 struct secref *const *p2 = b;
59 /* No signed difference calculation is correct here, since the
60 terms are unsigned and could be more than INT64_MAX apart. */
61 if ((*p1)->start < (*p2)->start)
63 if ((*p1)->start > (*p2)->start)
70 cache_sections (Dwfl_Module *mod)
72 if (likely (mod->reloc_info != NULL))
73 return mod->reloc_info->count;
75 struct secref *refs = NULL;
79 if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
82 __libdwfl_seterrno (DWFL_E_LIBELF);
86 bool check_reloc_sections = false;
88 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
91 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
95 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
96 && mod->e_type == ET_REL)
98 /* This section might not yet have been looked at. */
99 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
101 &shdr->sh_addr) != DWFL_E_NOERROR)
103 shdr = gelf_getshdr (scn, &shdr_mem);
104 if (unlikely (shdr == NULL))
108 if (shdr->sh_flags & SHF_ALLOC)
110 const char *name = elf_strptr (mod->main.elf, shstrndx,
112 if (unlikely (name == NULL))
115 struct secref *newref = alloca (sizeof *newref);
117 newref->relocs = NULL;
119 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
120 newref->end = newref->start + shdr->sh_size;
126 if (mod->e_type == ET_REL
127 && shdr->sh_size != 0
128 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
129 && mod->dwfl->callbacks->section_address != NULL)
131 if (shdr->sh_info < elf_ndxscn (scn))
133 /* We've already looked at the section these relocs apply to. */
134 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
135 if (likely (tscn != NULL))
136 for (struct secref *sec = refs; sec != NULL; sec = sec->next)
137 if (sec->scn == tscn)
144 /* We'll have to do a second pass. */
145 check_reloc_sections = true;
149 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
150 if (mod->reloc_info == NULL)
152 __libdwfl_seterrno (DWFL_E_NOMEM);
156 struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]);
157 for (size_t i = nrefs; i-- > 0; refs = refs->next)
159 assert (refs == NULL);
161 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
163 mod->reloc_info->count = nrefs;
164 for (size_t i = 0; i < nrefs; ++i)
166 mod->reloc_info->refs[i].name = sortrefs[i]->name;
167 mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
168 mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
169 mod->reloc_info->refs[i].start = sortrefs[i]->start;
170 mod->reloc_info->refs[i].end = sortrefs[i]->end;
173 if (unlikely (check_reloc_sections))
175 /* There was a reloc section that preceded its target section.
176 So we have to scan again now that we have cached all the
177 possible target sections we care about. */
180 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
183 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
187 if (shdr->sh_size != 0
188 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
190 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
191 if (likely (tscn != NULL))
192 for (size_t i = 0; i < nrefs; ++i)
193 if (mod->reloc_info->refs[i].scn == tscn)
195 mod->reloc_info->refs[i].relocs = scn;
207 dwfl_module_relocations (Dwfl_Module *mod)
215 return cache_sections (mod);
221 assert (mod->main.vaddr == mod->low_addr);
229 dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
251 if (cache_sections (mod) < 0)
254 struct dwfl_relocation *sections = mod->reloc_info;
256 if (idx >= sections->count)
260 *shndxp = elf_ndxscn (sections->refs[idx].scn);
262 return sections->refs[idx].name;
265 /* Check that MOD is valid and make sure its relocation has been done. */
267 check_module (Dwfl_Module *mod)
269 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
271 Dwfl_Error error = dwfl_errno ();
272 if (error != DWFL_E_NO_SYMTAB)
274 __libdwfl_seterrno (error);
282 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
284 Dwfl_Error error = dwfl_errno ();
285 if (error != DWFL_E_NO_DWARF)
287 __libdwfl_seterrno (error);
296 /* Find the index in MOD->reloc_info.refs containing *ADDR. */
298 find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
300 if (cache_sections (mod) < 0)
303 struct dwfl_relocation *sections = mod->reloc_info;
305 /* The sections are sorted by address, so we can use binary search. */
306 size_t l = 0, u = sections->count;
309 size_t idx = (l + u) / 2;
310 if (*addr < sections->refs[idx].start)
312 else if (*addr > sections->refs[idx].end)
316 /* Consider the limit of a section to be inside it, unless it's
317 inside the next one. A section limit address can appear in
319 if (*addr == sections->refs[idx].end
320 && idx + 1 < sections->count
321 && *addr == sections->refs[idx + 1].start)
324 *addr -= sections->refs[idx].start;
329 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
335 __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
337 int idx = find_section (mod, addr);
338 if (unlikely (idx == -1))
341 return elf_ndxscn (mod->reloc_info->refs[idx].scn);
345 dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
347 if (unlikely (check_module (mod)))
353 return find_section (mod, addr);
356 /* All relative to first and only relocation base: module start. */
357 *addr -= mod->low_addr;
361 /* Already absolute, dwfl_module_relocations returned zero. We
362 shouldn't really have been called, but it's a harmless no-op. */
368 INTDEF (dwfl_module_relocate_address)
371 dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
374 if (check_module (mod))
377 int idx = find_section (mod, address);
381 if (mod->reloc_info->refs[idx].relocs != NULL)
383 assert (mod->e_type == ET_REL);
385 Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
386 Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
387 Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
388 relocscn, tscn, true);
389 if (likely (result == DWFL_E_NOERROR))
390 mod->reloc_info->refs[idx].relocs = NULL;
393 __libdwfl_seterrno (result);
398 *bias = dwfl_adjusted_address (mod, 0);
399 return mod->reloc_info->refs[idx].scn;
401 INTDEF (dwfl_module_address_section)