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/>. */
35 struct dwfl_relocation
58 compare_secrefs (const void *a, const void *b)
60 struct secref *const *p1 = a;
61 struct secref *const *p2 = b;
63 /* No signed difference calculation is correct here, since the
64 terms are unsigned and could be more than INT64_MAX apart. */
65 if ((*p1)->start < (*p2)->start)
67 if ((*p1)->start > (*p2)->start)
70 if ((*p1)->end < (*p2)->end)
72 if ((*p1)->end > (*p2)->end)
75 /* Same start/end, then just compare which section came first. */
76 return elf_ndxscn ((*p1)->scn) - elf_ndxscn ((*p2)->scn);
80 cache_sections (Dwfl_Module *mod)
82 if (likely (mod->reloc_info != NULL))
83 return mod->reloc_info->count;
85 struct secref *refs = NULL;
89 if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
92 __libdwfl_seterrno (DWFL_E_LIBELF);
97 bool check_reloc_sections = false;
99 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
102 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
106 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
107 && mod->e_type == ET_REL)
109 /* This section might not yet have been looked at. */
110 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
112 &shdr->sh_addr) != DWFL_E_NOERROR)
114 shdr = gelf_getshdr (scn, &shdr_mem);
115 if (unlikely (shdr == NULL))
119 if (shdr->sh_flags & SHF_ALLOC)
121 const char *name = elf_strptr (mod->main.elf, shstrndx,
123 if (unlikely (name == NULL))
126 struct secref *newref = malloc (sizeof *newref);
127 if (unlikely (newref == NULL))
130 __libdwfl_seterrno (DWFL_E_NOMEM);
136 newref->relocs = NULL;
138 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
139 newref->end = newref->start + shdr->sh_size;
145 if (mod->e_type == ET_REL
146 && shdr->sh_size != 0
147 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
148 && mod->dwfl->callbacks->section_address != NULL)
150 if (shdr->sh_info < elf_ndxscn (scn))
152 /* We've already looked at the section these relocs apply to. */
153 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
154 if (likely (tscn != NULL))
155 for (struct secref *sec = refs; sec != NULL; sec = sec->next)
156 if (sec->scn == tscn)
163 /* We'll have to do a second pass. */
164 check_reloc_sections = true;
168 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
169 if (unlikely (mod->reloc_info == NULL))
172 struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
173 if (unlikely (sortrefs == NULL))
176 for (size_t i = nrefs; i-- > 0; refs = refs->next)
178 assert (refs == NULL);
180 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
182 mod->reloc_info->count = nrefs;
183 for (size_t i = 0; i < nrefs; ++i)
185 mod->reloc_info->refs[i].name = sortrefs[i]->name;
186 mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
187 mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
188 mod->reloc_info->refs[i].start = sortrefs[i]->start;
189 mod->reloc_info->refs[i].end = sortrefs[i]->end;
195 if (unlikely (check_reloc_sections))
197 /* There was a reloc section that preceded its target section.
198 So we have to scan again now that we have cached all the
199 possible target sections we care about. */
202 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
205 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
209 if (shdr->sh_size != 0
210 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
212 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
213 if (likely (tscn != NULL))
214 for (size_t i = 0; i < nrefs; ++i)
215 if (mod->reloc_info->refs[i].scn == tscn)
217 mod->reloc_info->refs[i].relocs = scn;
227 struct secref *ref = refs;
237 dwfl_module_relocations (Dwfl_Module *mod)
245 return cache_sections (mod);
251 assert (mod->main.vaddr == mod->low_addr);
259 dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
281 if (cache_sections (mod) < 0)
284 struct dwfl_relocation *sections = mod->reloc_info;
286 if (idx >= sections->count)
290 *shndxp = elf_ndxscn (sections->refs[idx].scn);
292 return sections->refs[idx].name;
295 /* Check that MOD is valid and make sure its relocation has been done. */
297 check_module (Dwfl_Module *mod)
302 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
304 Dwfl_Error error = dwfl_errno ();
305 if (error != DWFL_E_NO_SYMTAB)
307 __libdwfl_seterrno (error);
315 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
317 Dwfl_Error error = dwfl_errno ();
318 if (error != DWFL_E_NO_DWARF)
320 __libdwfl_seterrno (error);
329 /* Find the index in MOD->reloc_info.refs containing *ADDR. */
331 find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
333 if (cache_sections (mod) < 0)
336 struct dwfl_relocation *sections = mod->reloc_info;
338 /* The sections are sorted by address, so we can use binary search. */
339 size_t l = 0, u = sections->count;
342 size_t idx = (l + u) / 2;
343 if (*addr < sections->refs[idx].start)
345 else if (*addr > sections->refs[idx].end)
349 /* Consider the limit of a section to be inside it, unless it's
350 inside the next one. A section limit address can appear in
352 if (*addr == sections->refs[idx].end
353 && idx + 1 < sections->count
354 && *addr == sections->refs[idx + 1].start)
357 *addr -= sections->refs[idx].start;
362 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
368 __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
370 int idx = find_section (mod, addr);
371 if (unlikely (idx == -1))
374 return elf_ndxscn (mod->reloc_info->refs[idx].scn);
378 dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
380 if (unlikely (check_module (mod)))
386 return find_section (mod, addr);
389 /* All relative to first and only relocation base: module start. */
390 *addr -= mod->low_addr;
394 /* Already absolute, dwfl_module_relocations returned zero. We
395 shouldn't really have been called, but it's a harmless no-op. */
401 INTDEF (dwfl_module_relocate_address)
404 dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
407 if (check_module (mod))
410 int idx = find_section (mod, address);
414 if (mod->reloc_info->refs[idx].relocs != NULL)
416 assert (mod->e_type == ET_REL);
418 Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
419 Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
420 Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
421 relocscn, tscn, true);
422 if (likely (result == DWFL_E_NOERROR))
423 mod->reloc_info->refs[idx].relocs = NULL;
426 __libdwfl_seterrno (result);
431 *bias = dwfl_adjusted_address (mod, 0);
432 return mod->reloc_info->refs[idx].scn;
434 INTDEF (dwfl_module_address_section)