blob: 439a24e3b88d0247e280f2f1954de7480498ba26 [file] [log] [blame]
Roland McGrathd17fac72005-08-23 08:20:21 +00001/* Recover relocatibility for addresses computed from debug information.
Mark Wielaardbe177862015-05-18 16:23:06 +02002 Copyright (C) 2005-2010, 2013, 2015 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);
Mark Wielaardbe177862015-05-18 16:23:06 +020083 nrefs = -1;
84 goto free_refs;
Roland McGrathd17fac72005-08-23 08:20:21 +000085 }
86
Roland McGrathe4c22ea2007-10-23 13:07:39 +000087 bool check_reloc_sections = false;
Roland McGrathd17fac72005-08-23 08:20:21 +000088 Elf_Scn *scn = NULL;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000089 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
Roland McGrathd17fac72005-08-23 08:20:21 +000090 {
91 GElf_Shdr shdr_mem;
92 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
93 if (shdr == NULL)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000094 goto elf_error;
Roland McGrathd17fac72005-08-23 08:20:21 +000095
Roland McGrath19a8e4d2009-04-21 15:44:07 -070096 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
97 && mod->e_type == ET_REL)
Ulrich Drepperaa915fd2007-02-05 07:25:33 +000098 {
99 /* This section might not yet have been looked at. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000100 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
101 elf_ndxscn (scn),
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000102 &shdr->sh_addr) != DWFL_E_NOERROR)
103 continue;
104 shdr = gelf_getshdr (scn, &shdr_mem);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000105 if (unlikely (shdr == NULL))
106 goto elf_error;
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000107 }
108
109 if (shdr->sh_flags & SHF_ALLOC)
Roland McGrathd17fac72005-08-23 08:20:21 +0000110 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000111 const char *name = elf_strptr (mod->main.elf, shstrndx,
Roland McGrathd17fac72005-08-23 08:20:21 +0000112 shdr->sh_name);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000113 if (unlikely (name == NULL))
114 goto elf_error;
Roland McGrathd17fac72005-08-23 08:20:21 +0000115
Mark Wielaardbe177862015-05-18 16:23:06 +0200116 struct secref *newref = malloc (sizeof *newref);
117 if (unlikely (newref == NULL))
118 {
119 nomem:
120 __libdwfl_seterrno (DWFL_E_NOMEM);
121 nrefs = -1;
122 goto free_refs;
123 }
124
Roland McGrathd17fac72005-08-23 08:20:21 +0000125 newref->scn = scn;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000126 newref->relocs = NULL;
Roland McGrathd17fac72005-08-23 08:20:21 +0000127 newref->name = name;
Roland McGrath1743d7f2010-11-12 16:46:47 -0800128 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
Roland McGrath43da9892007-04-16 23:13:37 +0000129 newref->end = newref->start + shdr->sh_size;
Roland McGrathd17fac72005-08-23 08:20:21 +0000130 newref->next = refs;
131 refs = newref;
132 ++nrefs;
133 }
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000134
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)
139 {
140 if (shdr->sh_info < elf_ndxscn (scn))
141 {
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)
147 {
148 sec->relocs = scn;
149 break;
150 }
151 }
152 else
153 /* We'll have to do a second pass. */
154 check_reloc_sections = true;
155 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000156 }
157
158 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
Mark Wielaardbe177862015-05-18 16:23:06 +0200159 if (unlikely (mod->reloc_info == NULL))
160 goto nomem;
Roland McGrathd17fac72005-08-23 08:20:21 +0000161
Mark Wielaardbe177862015-05-18 16:23:06 +0200162 struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
163 if (unlikely (sortrefs == NULL))
164 goto nomem;
165
Roland McGrathd17fac72005-08-23 08:20:21 +0000166 for (size_t i = nrefs; i-- > 0; refs = refs->next)
167 sortrefs[i] = refs;
168 assert (refs == NULL);
169
170 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
171
172 mod->reloc_info->count = nrefs;
173 for (size_t i = 0; i < nrefs; ++i)
174 {
175 mod->reloc_info->refs[i].name = sortrefs[i]->name;
176 mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000177 mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
Roland McGrathd17fac72005-08-23 08:20:21 +0000178 mod->reloc_info->refs[i].start = sortrefs[i]->start;
179 mod->reloc_info->refs[i].end = sortrefs[i]->end;
Mark Wielaard93d89592015-06-06 22:49:34 +0200180 free (sortrefs[i]);
Roland McGrathd17fac72005-08-23 08:20:21 +0000181 }
182
Mark Wielaardbe177862015-05-18 16:23:06 +0200183 free (sortrefs);
184
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000185 if (unlikely (check_reloc_sections))
186 {
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. */
190
191 scn = NULL;
192 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
193 {
194 GElf_Shdr shdr_mem;
195 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
196 if (shdr == NULL)
197 goto elf_error;
198
199 if (shdr->sh_size != 0
200 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
201 {
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)
206 {
207 mod->reloc_info->refs[i].relocs = scn;
208 break;
209 }
210 }
211 }
212 }
213
Mark Wielaardbe177862015-05-18 16:23:06 +0200214free_refs:
215 while (refs != NULL)
216 {
217 struct secref *ref = refs;
218 refs = ref->next;
219 free (ref);
220 }
221
Roland McGrathd17fac72005-08-23 08:20:21 +0000222 return nrefs;
223}
224
225
226int
227dwfl_module_relocations (Dwfl_Module *mod)
228{
229 if (mod == NULL)
230 return -1;
231
Roland McGrathd17fac72005-08-23 08:20:21 +0000232 switch (mod->e_type)
233 {
234 case ET_REL:
235 return cache_sections (mod);
236
237 case ET_DYN:
238 return 1;
239
240 case ET_EXEC:
Roland McGrath1743d7f2010-11-12 16:46:47 -0800241 assert (mod->main.vaddr == mod->low_addr);
Roland McGrathd17fac72005-08-23 08:20:21 +0000242 break;
243 }
244
245 return 0;
246}
247
248const char *
249dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
250 Elf32_Word *shndxp)
251{
252 if (mod == NULL)
253 return NULL;
254
255 switch (mod->e_type)
256 {
257 case ET_REL:
258 break;
259
260 case ET_DYN:
261 if (idx != 0)
262 return NULL;
263 if (shndxp)
264 *shndxp = SHN_ABS;
265 return "";
266
267 default:
268 return NULL;
269 }
270
Mark Wielaardf43feb52011-10-20 16:53:54 +0200271 if (cache_sections (mod) < 0)
Roland McGrathd17fac72005-08-23 08:20:21 +0000272 return NULL;
273
274 struct dwfl_relocation *sections = mod->reloc_info;
275
276 if (idx >= sections->count)
277 return NULL;
278
279 if (shndxp)
280 *shndxp = elf_ndxscn (sections->refs[idx].scn);
281
282 return sections->refs[idx].name;
283}
284
Roland McGrath43da9892007-04-16 23:13:37 +0000285/* Check that MOD is valid and make sure its relocation has been done. */
286static bool
287check_module (Dwfl_Module *mod)
Roland McGrathd17fac72005-08-23 08:20:21 +0000288{
Mark Wielaarde115bda2015-05-24 00:07:33 +0200289 if (mod == NULL)
290 return true;
291
Roland McGrath43da9892007-04-16 23:13:37 +0000292 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
293 {
294 Dwfl_Error error = dwfl_errno ();
295 if (error != DWFL_E_NO_SYMTAB)
296 {
297 __libdwfl_seterrno (error);
298 return true;
299 }
300 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000301
302 if (mod->dw == NULL)
303 {
304 Dwarf_Addr bias;
305 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
Roland McGrath43da9892007-04-16 23:13:37 +0000306 {
307 Dwfl_Error error = dwfl_errno ();
308 if (error != DWFL_E_NO_DWARF)
309 {
310 __libdwfl_seterrno (error);
311 return true;
312 }
313 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000314 }
315
Roland McGrath43da9892007-04-16 23:13:37 +0000316 return false;
317}
Roland McGrathd17fac72005-08-23 08:20:21 +0000318
Roland McGrath43da9892007-04-16 23:13:37 +0000319/* Find the index in MOD->reloc_info.refs containing *ADDR. */
320static int
321find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
322{
Mark Wielaardf43feb52011-10-20 16:53:54 +0200323 if (cache_sections (mod) < 0)
Roland McGrathd17fac72005-08-23 08:20:21 +0000324 return -1;
325
326 struct dwfl_relocation *sections = mod->reloc_info;
327
328 /* The sections are sorted by address, so we can use binary search. */
329 size_t l = 0, u = sections->count;
330 while (l < u)
331 {
332 size_t idx = (l + u) / 2;
333 if (*addr < sections->refs[idx].start)
334 u = idx;
335 else if (*addr > sections->refs[idx].end)
336 l = idx + 1;
337 else
338 {
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
341 line records. */
342 if (*addr == sections->refs[idx].end
Mark Wielaard5b257822012-10-01 16:10:46 +0200343 && idx + 1 < sections->count
Roland McGrathd17fac72005-08-23 08:20:21 +0000344 && *addr == sections->refs[idx + 1].start)
345 ++idx;
346
347 *addr -= sections->refs[idx].start;
348 return idx;
349 }
350 }
351
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000352 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
Roland McGrathd17fac72005-08-23 08:20:21 +0000353 return -1;
354}
Roland McGrath43da9892007-04-16 23:13:37 +0000355
Mark Wielaard159ac522013-12-18 11:05:54 +0100356size_t
357internal_function
358__libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
359{
360 int idx = find_section (mod, addr);
361 if (unlikely (idx == -1))
362 return SHN_UNDEF;
363
364 return elf_ndxscn (mod->reloc_info->refs[idx].scn);
365}
366
Roland McGrath43da9892007-04-16 23:13:37 +0000367int
368dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
369{
Roland McGrath7d9b8212008-12-18 15:08:09 -0800370 if (unlikely (check_module (mod)))
Roland McGrath43da9892007-04-16 23:13:37 +0000371 return -1;
372
Roland McGrath7d9b8212008-12-18 15:08:09 -0800373 switch (mod->e_type)
Roland McGrath43da9892007-04-16 23:13:37 +0000374 {
Roland McGrath7d9b8212008-12-18 15:08:09 -0800375 case ET_REL:
376 return find_section (mod, addr);
377
378 case ET_DYN:
379 /* All relative to first and only relocation base: module start. */
380 *addr -= mod->low_addr;
381 break;
382
383 default:
384 /* Already absolute, dwfl_module_relocations returned zero. We
385 shouldn't really have been called, but it's a harmless no-op. */
386 break;
Roland McGrath43da9892007-04-16 23:13:37 +0000387 }
388
Roland McGrath7d9b8212008-12-18 15:08:09 -0800389 return 0;
Roland McGrath43da9892007-04-16 23:13:37 +0000390}
Roland McGrathd17fac72005-08-23 08:20:21 +0000391INTDEF (dwfl_module_relocate_address)
Roland McGrath43da9892007-04-16 23:13:37 +0000392
393Elf_Scn *
394dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
395 Dwarf_Addr *bias)
396{
397 if (check_module (mod))
398 return NULL;
399
400 int idx = find_section (mod, address);
401 if (idx < 0)
402 return NULL;
403
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000404 if (mod->reloc_info->refs[idx].relocs != NULL)
405 {
406 assert (mod->e_type == ET_REL);
407
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;
414 else
415 {
416 __libdwfl_seterrno (result);
417 return NULL;
418 }
419 }
420
Roland McGrath1743d7f2010-11-12 16:46:47 -0800421 *bias = dwfl_adjusted_address (mod, 0);
Roland McGrath43da9892007-04-16 23:13:37 +0000422 return mod->reloc_info->refs[idx].scn;
423}
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000424INTDEF (dwfl_module_address_section)