Line data Source code
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
58 5540 : compare_secrefs (const void *a, const void *b)
59 : {
60 5540 : struct secref *const *p1 = a;
61 5540 : 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 5540 : if ((*p1)->start < (*p2)->start)
66 : return -1;
67 57 : if ((*p1)->start > (*p2)->start)
68 : return 1;
69 :
70 57 : if ((*p1)->end < (*p2)->end)
71 : return -1;
72 28 : if ((*p1)->end > (*p2)->end)
73 : return 1;
74 :
75 : /* Same start/end, then just compare which section came first. */
76 16 : return elf_ndxscn ((*p1)->scn) - elf_ndxscn ((*p2)->scn);
77 : }
78 :
79 : static int
80 177625 : cache_sections (Dwfl_Module *mod)
81 : {
82 177625 : if (likely (mod->reloc_info != NULL))
83 177487 : return mod->reloc_info->count;
84 :
85 138 : struct secref *refs = NULL;
86 138 : size_t nrefs = 0;
87 :
88 : size_t shstrndx;
89 138 : if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
90 : {
91 0 : elf_error:
92 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
93 0 : nrefs = -1;
94 0 : goto free_refs;
95 : }
96 :
97 : bool check_reloc_sections = false;
98 : Elf_Scn *scn = NULL;
99 4379 : while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
100 : {
101 : GElf_Shdr shdr_mem;
102 4241 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
103 4241 : if (shdr == NULL)
104 : goto elf_error;
105 :
106 4241 : if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
107 47 : && mod->e_type == ET_REL)
108 : {
109 : /* This section might not yet have been looked at. */
110 46 : if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
111 46 : elf_ndxscn (scn),
112 46 : &shdr->sh_addr) != DWFL_E_NOERROR)
113 0 : continue;
114 46 : shdr = gelf_getshdr (scn, &shdr_mem);
115 46 : if (unlikely (shdr == NULL))
116 : goto elf_error;
117 : }
118 :
119 4241 : if (shdr->sh_flags & SHF_ALLOC)
120 : {
121 2658 : const char *name = elf_strptr (mod->main.elf, shstrndx,
122 2658 : shdr->sh_name);
123 2658 : if (unlikely (name == NULL))
124 : goto elf_error;
125 :
126 2658 : struct secref *newref = malloc (sizeof *newref);
127 2658 : if (unlikely (newref == NULL))
128 : {
129 0 : nomem:
130 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
131 0 : nrefs = -1;
132 0 : goto free_refs;
133 : }
134 :
135 2658 : newref->scn = scn;
136 2658 : newref->relocs = NULL;
137 2658 : newref->name = name;
138 5316 : newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
139 2658 : newref->end = newref->start + shdr->sh_size;
140 2658 : newref->next = refs;
141 2658 : refs = newref;
142 2658 : ++nrefs;
143 : }
144 :
145 4241 : if (mod->e_type == ET_REL
146 1299 : && shdr->sh_size != 0
147 1011 : && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
148 89 : && mod->dwfl->callbacks->section_address != NULL)
149 : {
150 89 : if (shdr->sh_info < elf_ndxscn (scn))
151 : {
152 : /* We've already looked at the section these relocs apply to. */
153 89 : Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
154 89 : if (likely (tscn != NULL))
155 24 : for (struct secref *sec = refs; sec != NULL; sec = sec->next)
156 111 : if (sec->scn == tscn)
157 : {
158 87 : sec->relocs = scn;
159 87 : break;
160 : }
161 : }
162 : else
163 : /* We'll have to do a second pass. */
164 : check_reloc_sections = true;
165 : }
166 : }
167 :
168 138 : mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
169 138 : if (unlikely (mod->reloc_info == NULL))
170 : goto nomem;
171 :
172 138 : struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
173 138 : if (unlikely (sortrefs == NULL))
174 : goto nomem;
175 :
176 2658 : for (size_t i = nrefs; i-- > 0; refs = refs->next)
177 2658 : sortrefs[i] = refs;
178 138 : assert (refs == NULL);
179 :
180 138 : qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
181 :
182 138 : mod->reloc_info->count = nrefs;
183 2796 : for (size_t i = 0; i < nrefs; ++i)
184 : {
185 2658 : mod->reloc_info->refs[i].name = sortrefs[i]->name;
186 2658 : mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
187 2658 : mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
188 2658 : mod->reloc_info->refs[i].start = sortrefs[i]->start;
189 2658 : mod->reloc_info->refs[i].end = sortrefs[i]->end;
190 2658 : free (sortrefs[i]);
191 : }
192 :
193 138 : free (sortrefs);
194 :
195 138 : 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 0 : while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
203 : {
204 : GElf_Shdr shdr_mem;
205 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
206 0 : if (shdr == NULL)
207 : goto elf_error;
208 :
209 0 : if (shdr->sh_size != 0
210 0 : && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
211 : {
212 0 : Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
213 0 : if (likely (tscn != NULL))
214 0 : for (size_t i = 0; i < nrefs; ++i)
215 0 : if (mod->reloc_info->refs[i].scn == tscn)
216 : {
217 0 : mod->reloc_info->refs[i].relocs = scn;
218 0 : break;
219 : }
220 : }
221 : }
222 : }
223 :
224 276 : free_refs:
225 138 : while (refs != NULL)
226 : {
227 0 : struct secref *ref = refs;
228 0 : refs = ref->next;
229 0 : free (ref);
230 : }
231 :
232 138 : return nrefs;
233 : }
234 :
235 :
236 : int
237 607191 : dwfl_module_relocations (Dwfl_Module *mod)
238 : {
239 607191 : if (mod == NULL)
240 : return -1;
241 :
242 607191 : switch (mod->e_type)
243 : {
244 53731 : case ET_REL:
245 53731 : return cache_sections (mod);
246 :
247 : case ET_DYN:
248 : return 1;
249 :
250 1005 : case ET_EXEC:
251 1005 : assert (mod->main.vaddr == mod->low_addr);
252 : break;
253 : }
254 :
255 1005 : return 0;
256 : }
257 :
258 : const char *
259 606195 : dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
260 : Elf32_Word *shndxp)
261 : {
262 606195 : if (mod == NULL)
263 : return NULL;
264 :
265 606195 : switch (mod->e_type)
266 : {
267 : case ET_REL:
268 : break;
269 :
270 552457 : case ET_DYN:
271 552457 : if (idx != 0)
272 : return NULL;
273 552457 : if (shndxp)
274 0 : *shndxp = SHN_ABS;
275 : return "";
276 :
277 : default:
278 : return NULL;
279 : }
280 :
281 53738 : if (cache_sections (mod) < 0)
282 : return NULL;
283 :
284 53738 : struct dwfl_relocation *sections = mod->reloc_info;
285 :
286 53738 : if (idx >= sections->count)
287 : return NULL;
288 :
289 53738 : if (shndxp)
290 0 : *shndxp = elf_ndxscn (sections->refs[idx].scn);
291 :
292 53738 : return sections->refs[idx].name;
293 : }
294 :
295 : /* Check that MOD is valid and make sure its relocation has been done. */
296 : static bool
297 606450 : check_module (Dwfl_Module *mod)
298 : {
299 606450 : if (mod == NULL)
300 : return true;
301 :
302 606450 : if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
303 : {
304 0 : Dwfl_Error error = dwfl_errno ();
305 0 : if (error != DWFL_E_NO_SYMTAB)
306 : {
307 0 : __libdwfl_seterrno (error);
308 0 : return true;
309 : }
310 : }
311 :
312 606450 : if (mod->dw == NULL)
313 : {
314 : Dwarf_Addr bias;
315 1011 : if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
316 : {
317 1000 : Dwfl_Error error = dwfl_errno ();
318 1000 : if (error != DWFL_E_NO_DWARF)
319 : {
320 0 : __libdwfl_seterrno (error);
321 0 : 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
331 70156 : find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
332 : {
333 70156 : if (cache_sections (mod) < 0)
334 : return -1;
335 :
336 70156 : struct dwfl_relocation *sections = mod->reloc_info;
337 :
338 : /* The sections are sorted by address, so we can use binary search. */
339 70156 : size_t l = 0, u = sections->count;
340 384580 : while (l < u)
341 : {
342 314415 : size_t idx = (l + u) / 2;
343 314415 : if (*addr < sections->refs[idx].start)
344 : u = idx;
345 84450 : else if (*addr > sections->refs[idx].end)
346 14303 : 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 70147 : if (*addr == sections->refs[idx].end
353 230 : && idx + 1 < sections->count
354 229 : && *addr == sections->refs[idx + 1].start)
355 141 : ++idx;
356 :
357 70147 : *addr -= sections->refs[idx].start;
358 70147 : return idx;
359 : }
360 : }
361 :
362 9 : __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
363 9 : return -1;
364 : }
365 :
366 : size_t
367 : internal_function
368 16340 : __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
369 : {
370 16340 : int idx = find_section (mod, addr);
371 16340 : if (unlikely (idx == -1))
372 : return SHN_UNDEF;
373 :
374 16331 : return elf_ndxscn (mod->reloc_info->refs[idx].scn);
375 : }
376 :
377 : int
378 606376 : dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
379 : {
380 606376 : if (unlikely (check_module (mod)))
381 : return -1;
382 :
383 606376 : switch (mod->e_type)
384 : {
385 53742 : case ET_REL:
386 53742 : return find_section (mod, addr);
387 :
388 552618 : case ET_DYN:
389 : /* All relative to first and only relocation base: module start. */
390 552618 : *addr -= mod->low_addr;
391 552618 : 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 : }
401 : INTDEF (dwfl_module_relocate_address)
402 :
403 : Elf_Scn *
404 74 : dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
405 : Dwarf_Addr *bias)
406 : {
407 74 : if (check_module (mod))
408 : return NULL;
409 :
410 74 : int idx = find_section (mod, address);
411 74 : if (idx < 0)
412 : return NULL;
413 :
414 74 : if (mod->reloc_info->refs[idx].relocs != NULL)
415 : {
416 2 : assert (mod->e_type == ET_REL);
417 :
418 2 : Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
419 2 : Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
420 2 : Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
421 : relocscn, tscn, true);
422 2 : if (likely (result == DWFL_E_NOERROR))
423 2 : mod->reloc_info->refs[idx].relocs = NULL;
424 : else
425 : {
426 0 : __libdwfl_seterrno (result);
427 0 : return NULL;
428 : }
429 : }
430 :
431 74 : *bias = dwfl_adjusted_address (mod, 0);
432 74 : return mod->reloc_info->refs[idx].scn;
433 : }
434 : INTDEF (dwfl_module_address_section)
|