1 /* Recover relocatibility for addresses computed from debug information.
2 Copyright (C) 2005-2010 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 struct dwfl_relocation
75 compare_secrefs (const void *a, const void *b)
77 struct secref *const *p1 = a;
78 struct secref *const *p2 = b;
80 /* No signed difference calculation is correct here, since the
81 terms are unsigned and could be more than INT64_MAX apart. */
82 if ((*p1)->start < (*p2)->start)
84 if ((*p1)->start > (*p2)->start)
91 cache_sections (Dwfl_Module *mod)
93 if (likely (mod->reloc_info != NULL))
94 return mod->reloc_info->count;
96 struct secref *refs = NULL;
100 if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
103 __libdwfl_seterrno (DWFL_E_LIBELF);
107 bool check_reloc_sections = false;
109 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
112 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
116 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
117 && mod->e_type == ET_REL)
119 /* This section might not yet have been looked at. */
120 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
122 &shdr->sh_addr) != DWFL_E_NOERROR)
124 shdr = gelf_getshdr (scn, &shdr_mem);
125 if (unlikely (shdr == NULL))
129 if (shdr->sh_flags & SHF_ALLOC)
131 const char *name = elf_strptr (mod->main.elf, shstrndx,
133 if (unlikely (name == NULL))
136 struct secref *newref = alloca (sizeof *newref);
138 newref->relocs = NULL;
140 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
141 newref->end = newref->start + shdr->sh_size;
147 if (mod->e_type == ET_REL
148 && shdr->sh_size != 0
149 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
150 && mod->dwfl->callbacks->section_address != NULL)
152 if (shdr->sh_info < elf_ndxscn (scn))
154 /* We've already looked at the section these relocs apply to. */
155 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
156 if (likely (tscn != NULL))
157 for (struct secref *sec = refs; sec != NULL; sec = sec->next)
158 if (sec->scn == tscn)
165 /* We'll have to do a second pass. */
166 check_reloc_sections = true;
170 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
171 if (mod->reloc_info == NULL)
173 __libdwfl_seterrno (DWFL_E_NOMEM);
177 struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]);
178 for (size_t i = nrefs; i-- > 0; refs = refs->next)
180 assert (refs == NULL);
182 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
184 mod->reloc_info->count = nrefs;
185 for (size_t i = 0; i < nrefs; ++i)
187 mod->reloc_info->refs[i].name = sortrefs[i]->name;
188 mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
189 mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
190 mod->reloc_info->refs[i].start = sortrefs[i]->start;
191 mod->reloc_info->refs[i].end = sortrefs[i]->end;
194 if (unlikely (check_reloc_sections))
196 /* There was a reloc section that preceded its target section.
197 So we have to scan again now that we have cached all the
198 possible target sections we care about. */
201 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
204 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
208 if (shdr->sh_size != 0
209 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
211 Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
212 if (likely (tscn != NULL))
213 for (size_t i = 0; i < nrefs; ++i)
214 if (mod->reloc_info->refs[i].scn == tscn)
216 mod->reloc_info->refs[i].relocs = scn;
228 dwfl_module_relocations (Dwfl_Module *mod)
236 return cache_sections (mod);
242 assert (mod->main.vaddr == mod->low_addr);
250 dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
272 if (cache_sections (mod) < 0)
275 struct dwfl_relocation *sections = mod->reloc_info;
277 if (idx >= sections->count)
281 *shndxp = elf_ndxscn (sections->refs[idx].scn);
283 return sections->refs[idx].name;
286 /* Check that MOD is valid and make sure its relocation has been done. */
288 check_module (Dwfl_Module *mod)
290 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
292 Dwfl_Error error = dwfl_errno ();
293 if (error != DWFL_E_NO_SYMTAB)
295 __libdwfl_seterrno (error);
303 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
305 Dwfl_Error error = dwfl_errno ();
306 if (error != DWFL_E_NO_DWARF)
308 __libdwfl_seterrno (error);
317 /* Find the index in MOD->reloc_info.refs containing *ADDR. */
319 find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
321 if (cache_sections (mod) < 0)
324 struct dwfl_relocation *sections = mod->reloc_info;
326 /* The sections are sorted by address, so we can use binary search. */
327 size_t l = 0, u = sections->count;
330 size_t idx = (l + u) / 2;
331 if (*addr < sections->refs[idx].start)
333 else if (*addr > sections->refs[idx].end)
337 /* Consider the limit of a section to be inside it, unless it's
338 inside the next one. A section limit address can appear in
340 if (*addr == sections->refs[idx].end
341 && idx < sections->count
342 && *addr == sections->refs[idx + 1].start)
345 *addr -= sections->refs[idx].start;
350 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
355 dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
357 if (unlikely (check_module (mod)))
363 return find_section (mod, addr);
366 /* All relative to first and only relocation base: module start. */
367 *addr -= mod->low_addr;
371 /* Already absolute, dwfl_module_relocations returned zero. We
372 shouldn't really have been called, but it's a harmless no-op. */
378 INTDEF (dwfl_module_relocate_address)
381 dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
384 if (check_module (mod))
387 int idx = find_section (mod, address);
391 if (mod->reloc_info->refs[idx].relocs != NULL)
393 assert (mod->e_type == ET_REL);
395 Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
396 Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
397 Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
398 relocscn, tscn, true);
399 if (likely (result == DWFL_E_NOERROR))
400 mod->reloc_info->refs[idx].relocs = NULL;
403 __libdwfl_seterrno (result);
408 *bias = dwfl_adjusted_address (mod, 0);
409 return mod->reloc_info->refs[idx].scn;
411 INTDEF (dwfl_module_address_section)