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.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
7
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
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
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.
24
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/>. */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include "libdwflP.h"
34
35 struct dwfl_relocation
36 {
37 size_t count;
38 struct
39 {
40 Elf_Scn *scn;
41 Elf_Scn *relocs;
42 const char *name;
43 GElf_Addr start, end;
44 } refs[0];
45 };
46
47
48 struct secref
49 {
50 struct secref *next;
51 Elf_Scn *scn;
52 Elf_Scn *relocs;
53 const char *name;
54 GElf_Addr start, end;
55 };
56
57 static int
compare_secrefs(const void * a,const void * b)58 compare_secrefs (const void *a, const void *b)
59 {
60 struct secref *const *p1 = a;
61 struct secref *const *p2 = b;
62
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)
66 return -1;
67 if ((*p1)->start > (*p2)->start)
68 return 1;
69
70 if ((*p1)->end < (*p2)->end)
71 return -1;
72 if ((*p1)->end > (*p2)->end)
73 return 1;
74
75 /* Same start/end, then just compare which section came first. */
76 return elf_ndxscn ((*p1)->scn) - elf_ndxscn ((*p2)->scn);
77 }
78
79 static int
cache_sections(Dwfl_Module * mod)80 cache_sections (Dwfl_Module *mod)
81 {
82 if (likely (mod->reloc_info != NULL))
83 return mod->reloc_info->count;
84
85 struct secref *refs = NULL;
86 size_t nrefs = 0;
87
88 size_t shstrndx;
89 if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
90 {
91 elf_error:
92 __libdwfl_seterrno (DWFL_E_LIBELF);
93 nrefs = -1;
94 goto free_refs;
95 }
96
97 bool check_reloc_sections = false;
98 Elf_Scn *scn = NULL;
99 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
100 {
101 GElf_Shdr shdr_mem;
102 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
103 if (shdr == NULL)
104 goto elf_error;
105
106 if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
107 && mod->e_type == ET_REL)
108 {
109 /* This section might not yet have been looked at. */
110 if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
111 elf_ndxscn (scn),
112 &shdr->sh_addr) != DWFL_E_NOERROR)
113 continue;
114 shdr = gelf_getshdr (scn, &shdr_mem);
115 if (unlikely (shdr == NULL))
116 goto elf_error;
117 }
118
119 if (shdr->sh_flags & SHF_ALLOC)
120 {
121 const char *name = elf_strptr (mod->main.elf, shstrndx,
122 shdr->sh_name);
123 if (unlikely (name == NULL))
124 goto elf_error;
125
126 struct secref *newref = malloc (sizeof *newref);
127 if (unlikely (newref == NULL))
128 {
129 nomem:
130 __libdwfl_seterrno (DWFL_E_NOMEM);
131 nrefs = -1;
132 goto free_refs;
133 }
134
135 newref->scn = scn;
136 newref->relocs = NULL;
137 newref->name = name;
138 newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
139 newref->end = newref->start + shdr->sh_size;
140 newref->next = refs;
141 refs = newref;
142 ++nrefs;
143 }
144
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)
149 {
150 if (shdr->sh_info < elf_ndxscn (scn))
151 {
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)
157 {
158 sec->relocs = scn;
159 break;
160 }
161 }
162 else
163 /* We'll have to do a second pass. */
164 check_reloc_sections = true;
165 }
166 }
167
168 mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
169 if (unlikely (mod->reloc_info == NULL))
170 goto nomem;
171
172 struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
173 if (unlikely (sortrefs == NULL))
174 goto nomem;
175
176 for (size_t i = nrefs; i-- > 0; refs = refs->next)
177 sortrefs[i] = refs;
178 assert (refs == NULL);
179
180 qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
181
182 mod->reloc_info->count = nrefs;
183 for (size_t i = 0; i < nrefs; ++i)
184 {
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;
190 free (sortrefs[i]);
191 }
192
193 free (sortrefs);
194
195 if (unlikely (check_reloc_sections))
196 {
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. */
200
201 scn = NULL;
202 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
203 {
204 GElf_Shdr shdr_mem;
205 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
206 if (shdr == NULL)
207 goto elf_error;
208
209 if (shdr->sh_size != 0
210 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
211 {
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)
216 {
217 mod->reloc_info->refs[i].relocs = scn;
218 break;
219 }
220 }
221 }
222 }
223
224 free_refs:
225 while (refs != NULL)
226 {
227 struct secref *ref = refs;
228 refs = ref->next;
229 free (ref);
230 }
231
232 return nrefs;
233 }
234
235
236 int
dwfl_module_relocations(Dwfl_Module * mod)237 dwfl_module_relocations (Dwfl_Module *mod)
238 {
239 if (mod == NULL)
240 return -1;
241
242 switch (mod->e_type)
243 {
244 case ET_REL:
245 return cache_sections (mod);
246
247 case ET_DYN:
248 return 1;
249
250 case ET_EXEC:
251 assert (mod->main.vaddr == mod->low_addr);
252 break;
253 }
254
255 return 0;
256 }
257
258 const char *
dwfl_module_relocation_info(Dwfl_Module * mod,unsigned int idx,Elf32_Word * shndxp)259 dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
260 Elf32_Word *shndxp)
261 {
262 if (mod == NULL)
263 return NULL;
264
265 switch (mod->e_type)
266 {
267 case ET_REL:
268 break;
269
270 case ET_DYN:
271 if (idx != 0)
272 return NULL;
273 if (shndxp)
274 *shndxp = SHN_ABS;
275 return "";
276
277 default:
278 return NULL;
279 }
280
281 if (cache_sections (mod) < 0)
282 return NULL;
283
284 struct dwfl_relocation *sections = mod->reloc_info;
285
286 if (idx >= sections->count)
287 return NULL;
288
289 if (shndxp)
290 *shndxp = elf_ndxscn (sections->refs[idx].scn);
291
292 return sections->refs[idx].name;
293 }
294
295 /* Check that MOD is valid and make sure its relocation has been done. */
296 static bool
check_module(Dwfl_Module * mod)297 check_module (Dwfl_Module *mod)
298 {
299 if (mod == NULL)
300 return true;
301
302 if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
303 {
304 Dwfl_Error error = dwfl_errno ();
305 if (error != DWFL_E_NO_SYMTAB)
306 {
307 __libdwfl_seterrno (error);
308 return true;
309 }
310 }
311
312 if (mod->dw == NULL)
313 {
314 Dwarf_Addr bias;
315 if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
316 {
317 Dwfl_Error error = dwfl_errno ();
318 if (error != DWFL_E_NO_DWARF)
319 {
320 __libdwfl_seterrno (error);
321 return true;
322 }
323 }
324 }
325
326 return false;
327 }
328
329 /* Find the index in MOD->reloc_info.refs containing *ADDR. */
330 static int
find_section(Dwfl_Module * mod,Dwarf_Addr * addr)331 find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
332 {
333 if (cache_sections (mod) < 0)
334 return -1;
335
336 struct dwfl_relocation *sections = mod->reloc_info;
337
338 /* The sections are sorted by address, so we can use binary search. */
339 size_t l = 0, u = sections->count;
340 while (l < u)
341 {
342 size_t idx = (l + u) / 2;
343 if (*addr < sections->refs[idx].start)
344 u = idx;
345 else if (*addr > sections->refs[idx].end)
346 l = idx + 1;
347 else
348 {
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
351 line records. */
352 if (*addr == sections->refs[idx].end
353 && idx + 1 < sections->count
354 && *addr == sections->refs[idx + 1].start)
355 ++idx;
356
357 *addr -= sections->refs[idx].start;
358 return idx;
359 }
360 }
361
362 __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
363 return -1;
364 }
365
366 size_t
367 internal_function
__libdwfl_find_section_ndx(Dwfl_Module * mod,Dwarf_Addr * addr)368 __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
369 {
370 int idx = find_section (mod, addr);
371 if (unlikely (idx == -1))
372 return SHN_UNDEF;
373
374 return elf_ndxscn (mod->reloc_info->refs[idx].scn);
375 }
376
377 int
dwfl_module_relocate_address(Dwfl_Module * mod,Dwarf_Addr * addr)378 dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
379 {
380 if (unlikely (check_module (mod)))
381 return -1;
382
383 switch (mod->e_type)
384 {
385 case ET_REL:
386 return find_section (mod, addr);
387
388 case ET_DYN:
389 /* All relative to first and only relocation base: module start. */
390 *addr -= mod->low_addr;
391 break;
392
393 default:
394 /* Already absolute, dwfl_module_relocations returned zero. We
395 shouldn't really have been called, but it's a harmless no-op. */
396 break;
397 }
398
399 return 0;
400 }
INTDEF(dwfl_module_relocate_address)401 INTDEF (dwfl_module_relocate_address)
402
403 Elf_Scn *
404 dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
405 Dwarf_Addr *bias)
406 {
407 if (check_module (mod))
408 return NULL;
409
410 int idx = find_section (mod, address);
411 if (idx < 0)
412 return NULL;
413
414 if (mod->reloc_info->refs[idx].relocs != NULL)
415 {
416 assert (mod->e_type == ET_REL);
417
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;
424 else
425 {
426 __libdwfl_seterrno (result);
427 return NULL;
428 }
429 }
430
431 *bias = dwfl_adjusted_address (mod, 0);
432 return mod->reloc_info->refs[idx].scn;
433 }
434 INTDEF (dwfl_module_address_section)
435