blob: e3fcba8d7ad5f60095674b3835dccf03cf4196b8 [file] [log] [blame]
Roland McGrathd17fac72005-08-23 08:20:21 +00001/* Recover relocatibility for addresses computed from debug information.
Roland McGrath33d305f2010-11-30 17:39:55 -08002 Copyright (C) 2005-2010 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Roland McGrathd17fac72005-08-23 08:20:21 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Roland McGrathd17fac72005-08-23 08:20:21 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
11
12 or
13
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
17
18 or both in parallel, as here.
19
20 elfutils is distributed in the hope that it will be useful, but
Ulrich Drepper361df7d2006-04-04 21:38:57 +000021 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.
24
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Roland McGrathd17fac72005-08-23 08:20:21 +000028
29#include "libdwflP.h"
30
31struct dwfl_relocation
32{
33 size_t count;
34 struct
35 {
36 Elf_Scn *scn;
Roland McGrathe4c22ea2007-10-23 13:07:39 +000037 Elf_Scn *relocs;
Roland McGrathd17fac72005-08-23 08:20:21 +000038 const char *name;
39 GElf_Addr start, end;
40 } refs[0];
41};
42
43
44struct secref
45{
46 struct secref *next;
47 Elf_Scn *scn;
Roland McGrathe4c22ea2007-10-23 13:07:39 +000048 Elf_Scn *relocs;
Roland McGrathd17fac72005-08-23 08:20:21 +000049 const char *name;
50 GElf_Addr start, end;
51};
52
53static int
54compare_secrefs (const void *a, const void *b)
55{
56 struct secref *const *p1 = a;
57 struct secref *const *p2 = b;
58
Roland McGrath43da9892007-04-16 23:13:37 +000059 /* 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)
62 return -1;
63 if ((*p1)->start > (*p2)->start)
64 return 1;
65
66 return 0;
Roland McGrathd17fac72005-08-23 08:20:21 +000067}
68
69static int
70cache_sections (Dwfl_Module *mod)
71{
Mark Wielaardf43feb52011-10-20 16:53:54 +020072 if (likely (mod->reloc_info != NULL))
73 return mod->reloc_info->count;
74
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000075 struct secref *refs = NULL;
76 size_t nrefs = 0;
77
78 size_t shstrndx;
Ulrich Drepperf1894932009-06-13 15:55:42 -070079 if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
Roland McGrathd17fac72005-08-23 08:20:21 +000080 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000081 elf_error:
Roland McGrathd17fac72005-08-23 08:20:21 +000082 __libdwfl_seterrno (DWFL_E_LIBELF);
83 return -1;
84 }
85
Roland McGrathe4c22ea2007-10-23 13:07:39 +000086 bool check_reloc_sections = false;
Roland McGrathd17fac72005-08-23 08:20:21 +000087 Elf_Scn *scn = NULL;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000088 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
Roland McGrathd17fac72005-08-23 08:20:21 +000089 {
90 GElf_Shdr shdr_mem;
91 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
92 if (shdr == NULL)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000093 goto elf_error;
Roland McGrathd17fac72005-08-23 08:20:21 +000094
Roland McGrath19a8e4d2009-04-21 15:44:07 -070095 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
96 && mod->e_type == ET_REL)
Ulrich Drepperaa915fd2007-02-05 07:25:33 +000097 {
98 /* This section might not yet have been looked at. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000099 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
100 elf_ndxscn (scn),
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000101 &shdr->sh_addr) != DWFL_E_NOERROR)
102 continue;
103 shdr = gelf_getshdr (scn, &shdr_mem);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000104 if (unlikely (shdr == NULL))
105 goto elf_error;
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000106 }
107
108 if (shdr->sh_flags & SHF_ALLOC)
Roland McGrathd17fac72005-08-23 08:20:21 +0000109 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000110 const char *name = elf_strptr (mod->main.elf, shstrndx,
Roland McGrathd17fac72005-08-23 08:20:21 +0000111 shdr->sh_name);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000112 if (unlikely (name == NULL))
113 goto elf_error;
Roland McGrathd17fac72005-08-23 08:20:21 +0000114
115 struct secref *newref = alloca (sizeof *newref);
116 newref->scn = scn;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000117 newref->relocs = NULL;
Roland McGrathd17fac72005-08-23 08:20:21 +0000118 newref->name = name;
Roland McGrath1743d7f2010-11-12 16:46:47 -0800119 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
Roland McGrath43da9892007-04-16 23:13:37 +0000120 newref->end = newref->start + shdr->sh_size;
Roland McGrathd17fac72005-08-23 08:20:21 +0000121 newref->next = refs;
122 refs = newref;
123 ++nrefs;
124 }
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000125
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)
130 {
131 if (shdr->sh_info < elf_ndxscn (scn))
132 {
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)
138 {
139 sec->relocs = scn;
140 break;
141 }
142 }
143 else
144 /* We'll have to do a second pass. */
145 check_reloc_sections = true;
146 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000147 }
148
149 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
150 if (mod->reloc_info == NULL)
151 {
152 __libdwfl_seterrno (DWFL_E_NOMEM);
153 return -1;
154 }
155
Roland McGrathc373d852006-10-10 00:25:21 +0000156 struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]);
Roland McGrathd17fac72005-08-23 08:20:21 +0000157 for (size_t i = nrefs; i-- > 0; refs = refs->next)
158 sortrefs[i] = refs;
159 assert (refs == NULL);
160
161 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
162
163 mod->reloc_info->count = nrefs;
164 for (size_t i = 0; i < nrefs; ++i)
165 {
166 mod->reloc_info->refs[i].name = sortrefs[i]->name;
167 mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000168 mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
Roland McGrathd17fac72005-08-23 08:20:21 +0000169 mod->reloc_info->refs[i].start = sortrefs[i]->start;
170 mod->reloc_info->refs[i].end = sortrefs[i]->end;
171 }
172
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000173 if (unlikely (check_reloc_sections))
174 {
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. */
178
179 scn = NULL;
180 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
181 {
182 GElf_Shdr shdr_mem;
183 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
184 if (shdr == NULL)
185 goto elf_error;
186
187 if (shdr->sh_size != 0
188 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
189 {
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)
194 {
195 mod->reloc_info->refs[i].relocs = scn;
196 break;
197 }
198 }
199 }
200 }
201
Roland McGrathd17fac72005-08-23 08:20:21 +0000202 return nrefs;
203}
204
205
206int
207dwfl_module_relocations (Dwfl_Module *mod)
208{
209 if (mod == NULL)
210 return -1;
211
Roland McGrathd17fac72005-08-23 08:20:21 +0000212 switch (mod->e_type)
213 {
214 case ET_REL:
215 return cache_sections (mod);
216
217 case ET_DYN:
218 return 1;
219
220 case ET_EXEC:
Roland McGrath1743d7f2010-11-12 16:46:47 -0800221 assert (mod->main.vaddr == mod->low_addr);
Roland McGrathd17fac72005-08-23 08:20:21 +0000222 break;
223 }
224
225 return 0;
226}
227
228const char *
229dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
230 Elf32_Word *shndxp)
231{
232 if (mod == NULL)
233 return NULL;
234
235 switch (mod->e_type)
236 {
237 case ET_REL:
238 break;
239
240 case ET_DYN:
241 if (idx != 0)
242 return NULL;
243 if (shndxp)
244 *shndxp = SHN_ABS;
245 return "";
246
247 default:
248 return NULL;
249 }
250
Mark Wielaardf43feb52011-10-20 16:53:54 +0200251 if (cache_sections (mod) < 0)
Roland McGrathd17fac72005-08-23 08:20:21 +0000252 return NULL;
253
254 struct dwfl_relocation *sections = mod->reloc_info;
255
256 if (idx >= sections->count)
257 return NULL;
258
259 if (shndxp)
260 *shndxp = elf_ndxscn (sections->refs[idx].scn);
261
262 return sections->refs[idx].name;
263}
264
Roland McGrath43da9892007-04-16 23:13:37 +0000265/* Check that MOD is valid and make sure its relocation has been done. */
266static bool
267check_module (Dwfl_Module *mod)
Roland McGrathd17fac72005-08-23 08:20:21 +0000268{
Roland McGrath43da9892007-04-16 23:13:37 +0000269 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
270 {
271 Dwfl_Error error = dwfl_errno ();
272 if (error != DWFL_E_NO_SYMTAB)
273 {
274 __libdwfl_seterrno (error);
275 return true;
276 }
277 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000278
279 if (mod->dw == NULL)
280 {
281 Dwarf_Addr bias;
282 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
Roland McGrath43da9892007-04-16 23:13:37 +0000283 {
284 Dwfl_Error error = dwfl_errno ();
285 if (error != DWFL_E_NO_DWARF)
286 {
287 __libdwfl_seterrno (error);
288 return true;
289 }
290 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000291 }
292
Roland McGrath43da9892007-04-16 23:13:37 +0000293 return false;
294}
Roland McGrathd17fac72005-08-23 08:20:21 +0000295
Roland McGrath43da9892007-04-16 23:13:37 +0000296/* Find the index in MOD->reloc_info.refs containing *ADDR. */
297static int
298find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
299{
Mark Wielaardf43feb52011-10-20 16:53:54 +0200300 if (cache_sections (mod) < 0)
Roland McGrathd17fac72005-08-23 08:20:21 +0000301 return -1;
302
303 struct dwfl_relocation *sections = mod->reloc_info;
304
305 /* The sections are sorted by address, so we can use binary search. */
306 size_t l = 0, u = sections->count;
307 while (l < u)
308 {
309 size_t idx = (l + u) / 2;
310 if (*addr < sections->refs[idx].start)
311 u = idx;
312 else if (*addr > sections->refs[idx].end)
313 l = idx + 1;
314 else
315 {
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
318 line records. */
319 if (*addr == sections->refs[idx].end
320 && idx < sections->count
321 && *addr == sections->refs[idx + 1].start)
322 ++idx;
323
324 *addr -= sections->refs[idx].start;
325 return idx;
326 }
327 }
328
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000329 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
Roland McGrathd17fac72005-08-23 08:20:21 +0000330 return -1;
331}
Roland McGrath43da9892007-04-16 23:13:37 +0000332
333int
334dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
335{
Roland McGrath7d9b8212008-12-18 15:08:09 -0800336 if (unlikely (check_module (mod)))
Roland McGrath43da9892007-04-16 23:13:37 +0000337 return -1;
338
Roland McGrath7d9b8212008-12-18 15:08:09 -0800339 switch (mod->e_type)
Roland McGrath43da9892007-04-16 23:13:37 +0000340 {
Roland McGrath7d9b8212008-12-18 15:08:09 -0800341 case ET_REL:
342 return find_section (mod, addr);
343
344 case ET_DYN:
345 /* All relative to first and only relocation base: module start. */
346 *addr -= mod->low_addr;
347 break;
348
349 default:
350 /* Already absolute, dwfl_module_relocations returned zero. We
351 shouldn't really have been called, but it's a harmless no-op. */
352 break;
Roland McGrath43da9892007-04-16 23:13:37 +0000353 }
354
Roland McGrath7d9b8212008-12-18 15:08:09 -0800355 return 0;
Roland McGrath43da9892007-04-16 23:13:37 +0000356}
Roland McGrathd17fac72005-08-23 08:20:21 +0000357INTDEF (dwfl_module_relocate_address)
Roland McGrath43da9892007-04-16 23:13:37 +0000358
359Elf_Scn *
360dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
361 Dwarf_Addr *bias)
362{
363 if (check_module (mod))
364 return NULL;
365
366 int idx = find_section (mod, address);
367 if (idx < 0)
368 return NULL;
369
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000370 if (mod->reloc_info->refs[idx].relocs != NULL)
371 {
372 assert (mod->e_type == ET_REL);
373
374 Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
375 Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
376 Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
377 relocscn, tscn, true);
378 if (likely (result == DWFL_E_NOERROR))
379 mod->reloc_info->refs[idx].relocs = NULL;
380 else
381 {
382 __libdwfl_seterrno (result);
383 return NULL;
384 }
385 }
386
Roland McGrath1743d7f2010-11-12 16:46:47 -0800387 *bias = dwfl_adjusted_address (mod, 0);
Roland McGrath43da9892007-04-16 23:13:37 +0000388 return mod->reloc_info->refs[idx].scn;
389}
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000390INTDEF (dwfl_module_address_section)