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 5627 : compare_secrefs (const void *a, const void *b)
59 : {
60 5627 : struct secref *const *p1 = a;
61 5627 : 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 5627 : if ((*p1)->start < (*p2)->start)
66 : return -1;
67 51 : if ((*p1)->start > (*p2)->start)
68 : return 1;
69 :
70 51 : if ((*p1)->end < (*p2)->end)
71 : return -1;
72 22 : if ((*p1)->end > (*p2)->end)
73 : return 1;
74 :
75 : /* Same start/end, then just compare which section came first. */
76 10 : return elf_ndxscn ((*p1)->scn) - elf_ndxscn ((*p2)->scn);
77 : }
78 :
79 : static int
80 248834 : cache_sections (Dwfl_Module *mod)
81 : {
82 246138 : if (likely (mod->reloc_info != NULL))
83 246001 : return mod->reloc_info->count;
84 :
85 137 : struct secref *refs = NULL;
86 137 : size_t nrefs = 0;
87 :
88 : size_t shstrndx;
89 137 : if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
90 : {
91 : 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 4296 : while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
100 : {
101 : GElf_Shdr shdr_mem;
102 4159 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
103 4159 : if (shdr == NULL)
104 : goto elf_error;
105 :
106 4159 : if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
107 41 : && mod->e_type == ET_REL)
108 : {
109 : /* This section might not yet have been looked at. */
110 40 : if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
111 40 : elf_ndxscn (scn),
112 40 : &shdr->sh_addr) != DWFL_E_NOERROR)
113 0 : continue;
114 40 : shdr = gelf_getshdr (scn, &shdr_mem);
115 40 : if (unlikely (shdr == NULL))
116 : goto elf_error;
117 : }
118 :
119 4159 : if (shdr->sh_flags & SHF_ALLOC)
120 : {
121 2696 : const char *name = elf_strptr (mod->main.elf, shstrndx,
122 2696 : shdr->sh_name);
123 2696 : if (unlikely (name == NULL))
124 : goto elf_error;
125 :
126 2696 : struct secref *newref = malloc (sizeof *newref);
127 2696 : if (unlikely (newref == NULL))
128 : {
129 : nomem:
130 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
131 0 : nrefs = -1;
132 0 : goto free_refs;
133 : }
134 :
135 2696 : newref->scn = scn;
136 2696 : newref->relocs = NULL;
137 2696 : newref->name = name;
138 8088 : newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
139 2696 : newref->end = newref->start + shdr->sh_size;
140 2696 : newref->next = refs;
141 2696 : refs = newref;
142 2696 : ++nrefs;
143 : }
144 :
145 4159 : if (mod->e_type == ET_REL
146 1010 : && shdr->sh_size != 0
147 791 : && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
148 72 : && mod->dwfl->callbacks->section_address != NULL)
149 : {
150 72 : if (shdr->sh_info < elf_ndxscn (scn))
151 : {
152 : /* We've already looked at the section these relocs apply to. */
153 72 : Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
154 72 : if (likely (tscn != NULL))
155 0 : for (struct secref *sec = refs; sec != NULL; sec = sec->next)
156 72 : if (sec->scn == tscn)
157 : {
158 72 : sec->relocs = scn;
159 72 : break;
160 : }
161 : }
162 : else
163 : /* We'll have to do a second pass. */
164 : check_reloc_sections = true;
165 : }
166 : }
167 :
168 137 : mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
169 137 : if (unlikely (mod->reloc_info == NULL))
170 : goto nomem;
171 :
172 137 : struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
173 137 : if (unlikely (sortrefs == NULL))
174 : goto nomem;
175 :
176 2696 : for (size_t i = nrefs; i-- > 0; refs = refs->next)
177 2696 : sortrefs[i] = refs;
178 137 : assert (refs == NULL);
179 :
180 137 : qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
181 :
182 137 : mod->reloc_info->count = nrefs;
183 2833 : for (size_t i = 0; i < nrefs; ++i)
184 : {
185 2696 : mod->reloc_info->refs[i].name = sortrefs[i]->name;
186 2696 : mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
187 2696 : mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
188 2696 : mod->reloc_info->refs[i].start = sortrefs[i]->start;
189 2696 : mod->reloc_info->refs[i].end = sortrefs[i]->end;
190 2696 : free (sortrefs[i]);
191 : }
192 :
193 137 : free (sortrefs);
194 :
195 137 : 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 : free_refs:
225 137 : while (refs != NULL)
226 : {
227 0 : struct secref *ref = refs;
228 0 : refs = ref->next;
229 0 : free (ref);
230 : }
231 :
232 137 : return nrefs;
233 : }
234 :
235 :
236 : int
237 585260 : dwfl_module_relocations (Dwfl_Module *mod)
238 : {
239 585260 : if (mod == NULL)
240 : return -1;
241 :
242 585260 : switch (mod->e_type)
243 : {
244 : case ET_REL:
245 43446 : return cache_sections (mod);
246 :
247 : case ET_DYN:
248 : return 1;
249 :
250 : case ET_EXEC:
251 395335 : assert (mod->main.vaddr == mod->low_addr);
252 : break;
253 : }
254 :
255 395335 : return 0;
256 : }
257 :
258 : const char *
259 189934 : dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
260 : Elf32_Word *shndxp)
261 : {
262 189934 : if (mod == NULL)
263 : return NULL;
264 :
265 189934 : switch (mod->e_type)
266 : {
267 : case ET_REL:
268 : break;
269 :
270 : case ET_DYN:
271 146481 : if (idx != 0)
272 : return NULL;
273 146481 : if (shndxp)
274 0 : *shndxp = SHN_ABS;
275 : return "";
276 :
277 : default:
278 : return NULL;
279 : }
280 :
281 43453 : if (cache_sections (mod) < 0)
282 : return NULL;
283 :
284 43453 : struct dwfl_relocation *sections = mod->reloc_info;
285 :
286 43453 : if (idx >= sections->count)
287 : return NULL;
288 :
289 43453 : if (shndxp)
290 0 : *shndxp = elf_ndxscn (sections->refs[idx].scn);
291 :
292 43453 : 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 190189 : check_module (Dwfl_Module *mod)
298 : {
299 190189 : if (mod == NULL)
300 : return true;
301 :
302 190189 : 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 190189 : if (mod->dw == NULL)
313 : {
314 : Dwarf_Addr bias;
315 177 : if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
316 : {
317 166 : Dwfl_Error error = dwfl_errno ();
318 166 : 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 159239 : find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
332 : {
333 159239 : if (cache_sections (mod) < 0)
334 : return -1;
335 :
336 159239 : struct dwfl_relocation *sections = mod->reloc_info;
337 :
338 : /* The sections are sorted by address, so we can use binary search. */
339 159239 : size_t l = 0, u = sections->count;
340 788373 : while (l < u)
341 : {
342 629125 : size_t idx = (l + u) / 2;
343 629125 : if (*addr < sections->refs[idx].start)
344 : u = idx;
345 378534 : else if (*addr > sections->refs[idx].end)
346 219304 : 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 159230 : if (*addr == sections->refs[idx].end
353 3390 : && idx + 1 < sections->count
354 3389 : && *addr == sections->refs[idx + 1].start)
355 3352 : ++idx;
356 :
357 159230 : *addr -= sections->refs[idx].start;
358 159230 : 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 115708 : __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
369 : {
370 115708 : int idx = find_section (mod, addr);
371 115708 : if (unlikely (idx == -1))
372 : return SHN_UNDEF;
373 :
374 115699 : return elf_ndxscn (mod->reloc_info->refs[idx].scn);
375 : }
376 :
377 : int
378 190115 : dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
379 : {
380 190115 : if (unlikely (check_module (mod)))
381 : return -1;
382 :
383 190115 : switch (mod->e_type)
384 : {
385 : case ET_REL:
386 43457 : return find_section (mod, addr);
387 :
388 : case ET_DYN:
389 : /* All relative to first and only relocation base: module start. */
390 146642 : *addr -= mod->low_addr;
391 146642 : 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 148 : 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)
|