1 /* Recover relocatibility for addresses computed from debug information.
2 Copyright (C) 2005-2010, 2013, 2015 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);
87 bool check_reloc_sections = false;
89 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
92 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
96 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
97 && mod->e_type == ET_REL)
99 /* This section might not yet have been looked at. */
100 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
102 &shdr->sh_addr) != DWFL_E_NOERROR)
104 shdr = gelf_getshdr (scn, &shdr_mem);
105 if (unlikely (shdr == NULL))
109 if (shdr->sh_flags & SHF_ALLOC)
111 const char *name = elf_strptr (mod->main.elf, shstrndx,
113 if (unlikely (name == NULL))
116 struct secref *newref = malloc (sizeof *newref);
117 if (unlikely (newref == NULL))
120 __libdwfl_seterrno (DWFL_E_NOMEM);
126 newref->relocs = NULL;
128 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
129 newref->end = newref->start + shdr->sh_size;
135 if (mod->e_type == ET_REL
136 && shdr->sh_size != 0
137 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
138 && mod->dwfl->callbacks->section_address != NULL)
140 if (shdr->sh_info < elf_ndxscn (scn))
142 /* We've already looked at the section these relocs apply to. */
143 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
144 if (likely (tscn != NULL))
145 for (struct secref *sec = refs; sec != NULL; sec = sec->next)
146 if (sec->scn == tscn)
153 /* We'll have to do a second pass. */
154 check_reloc_sections = true;
158 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
159 if (unlikely (mod->reloc_info == NULL))
162 struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
163 if (unlikely (sortrefs == NULL))
166 for (size_t i = nrefs; i-- > 0; refs = refs->next)
168 assert (refs == NULL);
170 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
172 mod->reloc_info->count = nrefs;
173 for (size_t i = 0; i < nrefs; ++i)
175 mod->reloc_info->refs[i].name = sortrefs[i]->name;
176 mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
177 mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
178 mod->reloc_info->refs[i].start = sortrefs[i]->start;
179 mod->reloc_info->refs[i].end = sortrefs[i]->end;
185 if (unlikely (check_reloc_sections))
187 /* There was a reloc section that preceded its target section.
188 So we have to scan again now that we have cached all the
189 possible target sections we care about. */
192 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
195 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
199 if (shdr->sh_size != 0
200 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
202 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
203 if (likely (tscn != NULL))
204 for (size_t i = 0; i < nrefs; ++i)
205 if (mod->reloc_info->refs[i].scn == tscn)
207 mod->reloc_info->refs[i].relocs = scn;
217 struct secref *ref = refs;
227 dwfl_module_relocations (Dwfl_Module *mod)
235 return cache_sections (mod);
241 assert (mod->main.vaddr == mod->low_addr);
249 dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
271 if (cache_sections (mod) < 0)
274 struct dwfl_relocation *sections = mod->reloc_info;
276 if (idx >= sections->count)
280 *shndxp = elf_ndxscn (sections->refs[idx].scn);
282 return sections->refs[idx].name;
285 /* Check that MOD is valid and make sure its relocation has been done. */
287 check_module (Dwfl_Module *mod)
292 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
294 Dwfl_Error error = dwfl_errno ();
295 if (error != DWFL_E_NO_SYMTAB)
297 __libdwfl_seterrno (error);
305 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
307 Dwfl_Error error = dwfl_errno ();
308 if (error != DWFL_E_NO_DWARF)
310 __libdwfl_seterrno (error);
319 /* Find the index in MOD->reloc_info.refs containing *ADDR. */
321 find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
323 if (cache_sections (mod) < 0)
326 struct dwfl_relocation *sections = mod->reloc_info;
328 /* The sections are sorted by address, so we can use binary search. */
329 size_t l = 0, u = sections->count;
332 size_t idx = (l + u) / 2;
333 if (*addr < sections->refs[idx].start)
335 else if (*addr > sections->refs[idx].end)
339 /* Consider the limit of a section to be inside it, unless it's
340 inside the next one. A section limit address can appear in
342 if (*addr == sections->refs[idx].end
343 && idx + 1 < sections->count
344 && *addr == sections->refs[idx + 1].start)
347 *addr -= sections->refs[idx].start;
352 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
358 __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
360 int idx = find_section (mod, addr);
361 if (unlikely (idx == -1))
364 return elf_ndxscn (mod->reloc_info->refs[idx].scn);
368 dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
370 if (unlikely (check_module (mod)))
376 return find_section (mod, addr);
379 /* All relative to first and only relocation base: module start. */
380 *addr -= mod->low_addr;
384 /* Already absolute, dwfl_module_relocations returned zero. We
385 shouldn't really have been called, but it's a harmless no-op. */
391 INTDEF (dwfl_module_relocate_address)
394 dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
397 if (check_module (mod))
400 int idx = find_section (mod, address);
404 if (mod->reloc_info->refs[idx].relocs != NULL)
406 assert (mod->e_type == ET_REL);
408 Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
409 Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
410 Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
411 relocscn, tscn, true);
412 if (likely (result == DWFL_E_NOERROR))
413 mod->reloc_info->refs[idx].relocs = NULL;
416 __libdwfl_seterrno (result);
421 *bias = dwfl_adjusted_address (mod, 0);
422 return mod->reloc_info->refs[idx].scn;
424 INTDEF (dwfl_module_address_section)