Branch data Line data Source code
1 : : /* Find debugging and symbol information for a module in libdwfl.
2 : : Copyright (C) 2005-2012 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 : : #include "libdwflP.h"
30 : : #include <fcntl.h>
31 : : #include <string.h>
32 : : #include <unistd.h>
33 : : #include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
34 : : #include "../libelf/libelfP.h"
35 : :
36 : :
37 : : /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
38 : : When we return success, FILE->elf and FILE->vaddr are set up. */
39 : : static inline Dwfl_Error
40 : 5103 : open_elf (Dwfl_Module *mod, struct dwfl_file *file)
41 : : {
42 [ + + ]: 5103 : if (file->elf == NULL)
43 : : {
44 : : /* CBFAIL uses errno if it's set, so clear it first in case we don't
45 : : set it with an open failure below. */
46 : 5070 : errno = 0;
47 : :
48 : : /* If there was a pre-primed file name left that the callback left
49 : : behind, try to open that file name. */
50 [ + + ][ + + ]: 5070 : if (file->fd < 0 && file->name != NULL)
51 [ - + ][ # # ]: 8 : file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));
52 : :
53 [ + + ]: 5070 : if (file->fd < 0)
54 [ - + ]: 37 : return CBFAIL;
55 : :
56 : 5033 : Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
57 [ + - ]: 5033 : if (error != DWFL_E_NOERROR)
58 : : return error;
59 : : }
60 [ - + ]: 33 : else if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
61 : : {
62 : 0 : elf_end (file->elf);
63 : 0 : file->elf = NULL;
64 : 0 : close (file->fd);
65 : 0 : file->fd = -1;
66 : : return DWFL_E_BADELF;
67 : : }
68 : :
69 : 5066 : GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
70 [ - + ]: 5066 : if (ehdr == NULL)
71 : : {
72 : : elf_error:
73 : 0 : elf_end (file->elf);
74 : 0 : file->elf = NULL;
75 : 0 : close (file->fd);
76 : 0 : file->fd = -1;
77 : 0 : return DWFL_E (LIBELF, elf_errno ());
78 : : }
79 : :
80 [ + + ]: 5066 : if (mod->e_type != ET_REL)
81 : : {
82 : : /* In any non-ET_REL file, we compute the "synchronization address".
83 : :
84 : : We start with the address at the end of the first PT_LOAD
85 : : segment. When prelink converts REL to RELA in an ET_DYN
86 : : file, it expands the space between the beginning of the
87 : : segment and the actual code/data addresses. Since that
88 : : change wasn't made in the debug file, the distance from
89 : : p_vaddr to an address of interest (in an st_value or DWARF
90 : : data) now differs between the main and debug files. The
91 : : distance from address_sync to an address of interest remains
92 : : consistent.
93 : :
94 : : If there are no section headers at all (full stripping), then
95 : : the end of the first segment is a valid synchronization address.
96 : : This cannot happen in a prelinked file, since prelink itself
97 : : relies on section headers for prelinking and for undoing it.
98 : : (If you do full stripping on a prelinked file, then you get what
99 : : you deserve--you can neither undo the prelinking, nor expect to
100 : : line it up with a debug file separated before prelinking.)
101 : :
102 : : However, when prelink processes an ET_EXEC file, it can do
103 : : something different. There it juggles the "special" sections
104 : : (SHT_DYNSYM et al) to make space for the additional prelink
105 : : special sections. Sometimes it will do this by moving a special
106 : : section like .dynstr after the real program sections in the first
107 : : PT_LOAD segment--i.e. to the end. That changes the end address of
108 : : the segment, so it no longer lines up correctly and is not a valid
109 : : synchronization address to use. Because of this, we need to apply
110 : : a different prelink-savvy means to discover the synchronization
111 : : address when there is a separate debug file and a prelinked main
112 : : file. That is done in find_debuginfo, below. */
113 : :
114 : : size_t phnum;
115 [ + - ]: 5065 : if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
116 : : goto elf_error;
117 : :
118 : 5065 : file->vaddr = file->address_sync = 0;
119 [ + - ]: 20190 : for (size_t i = 0; i < phnum; ++i)
120 : : {
121 : : GElf_Phdr ph_mem;
122 : 15125 : GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
123 [ + - ]: 15125 : if (unlikely (ph == NULL))
124 : : goto elf_error;
125 [ + + ]: 15125 : if (ph->p_type == PT_LOAD)
126 : : {
127 : 5065 : file->vaddr = ph->p_vaddr & -ph->p_align;
128 : 5065 : file->address_sync = ph->p_vaddr + ph->p_memsz;
129 : : break;
130 : : }
131 : : }
132 : : }
133 : :
134 : 5066 : mod->e_type = ehdr->e_type;
135 : :
136 : : /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */
137 [ + + ][ + + ]: 5066 : if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
138 : 5103 : mod->e_type = ET_DYN;
139 : :
140 : : return DWFL_E_NOERROR;
141 : : }
142 : :
143 : : /* We have an authoritative build ID for this module MOD, so don't use
144 : : a file by name that doesn't match that ID. */
145 : : static void
146 : 6 : mod_verify_build_id (Dwfl_Module *mod)
147 : : {
148 [ - + ]: 6 : assert (mod->build_id_len > 0);
149 : :
150 [ - + - + ]: 6 : switch (__builtin_expect (__libdwfl_find_build_id (mod, false,
151 : : mod->main.elf), 2))
152 : : {
153 : : case 2:
154 : : /* Build ID matches as it should. */
155 : 6 : return;
156 : :
157 : : case -1: /* ELF error. */
158 : 0 : mod->elferr = INTUSE(dwfl_errno) ();
159 : 0 : break;
160 : :
161 : : case 0: /* File has no build ID note. */
162 : : case 1: /* FIle has a build ID that does not match. */
163 : 5 : mod->elferr = DWFL_E_WRONG_ID_ELF;
164 : 5 : break;
165 : :
166 : : default:
167 : 0 : abort ();
168 : : }
169 : :
170 : : /* We get here when it was the right ELF file. Clear it out. */
171 : 5 : elf_end (mod->main.elf);
172 : 5 : mod->main.elf = NULL;
173 [ + - ]: 5 : if (mod->main.fd >= 0)
174 : : {
175 : 5 : close (mod->main.fd);
176 : 5 : mod->main.fd = -1;
177 : : }
178 : : }
179 : :
180 : : /* Find the main ELF file for this module and open libelf on it.
181 : : When we return success, MOD->main.elf and MOD->main.bias are set up. */
182 : : void
183 : : internal_function
184 : 5439 : __libdwfl_getelf (Dwfl_Module *mod)
185 : : {
186 [ + + ]: 5439 : if (mod->main.elf != NULL /* Already done. */
187 [ + + ]: 5045 : || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */
188 : : return;
189 : :
190 : 5036 : mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
191 : : &mod->main.name,
192 : : &mod->main.elf);
193 [ + + ][ + + ]: 5036 : const bool fallback = mod->main.elf == NULL && mod->main.fd < 0;
194 : 5036 : mod->elferr = open_elf (mod, &mod->main);
195 [ + + ]: 5036 : if (mod->elferr != DWFL_E_NOERROR)
196 : : return;
197 : :
198 [ + + ]: 5034 : if (!mod->main.valid)
199 : : {
200 : : /* Clear any explicitly reported build ID, just in case it was wrong.
201 : : We'll fetch it from the file when asked. */
202 : 5028 : free (mod->build_id_bits);
203 : 5028 : mod->build_id_bits = NULL;
204 : 5028 : mod->build_id_len = 0;
205 : : }
206 [ + - ]: 6 : else if (fallback)
207 : 6 : mod_verify_build_id (mod);
208 : :
209 [ + - ]: 5439 : mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr;
210 : : }
211 : :
212 : : /* Search an ELF file for a ".gnu_debuglink" section. */
213 : : static const char *
214 : 65 : find_debuglink (Elf *elf, GElf_Word *crc)
215 : : {
216 : : size_t shstrndx;
217 [ + - ]: 65 : if (elf_getshdrstrndx (elf, &shstrndx) < 0)
218 : : return NULL;
219 : :
220 : : Elf_Scn *scn = NULL;
221 [ + + ]: 1219 : while ((scn = elf_nextscn (elf, scn)) != NULL)
222 : : {
223 : : GElf_Shdr shdr_mem;
224 : 1193 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
225 [ + - ]: 1193 : if (shdr == NULL)
226 : : return NULL;
227 : :
228 : 1193 : const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
229 [ + - ]: 1193 : if (name == NULL)
230 : : return NULL;
231 : :
232 [ + + ]: 1193 : if (!strcmp (name, ".gnu_debuglink"))
233 : : break;
234 : : }
235 : :
236 [ + + ]: 65 : if (scn == NULL)
237 : : return NULL;
238 : :
239 : : /* Found the .gnu_debuglink section. Extract its contents. */
240 : 39 : Elf_Data *rawdata = elf_rawdata (scn, NULL);
241 [ + - ]: 39 : if (rawdata == NULL)
242 : : return NULL;
243 : :
244 : 39 : Elf_Data crcdata =
245 : : {
246 : : .d_type = ELF_T_WORD,
247 : : .d_buf = crc,
248 : : .d_size = sizeof *crc,
249 : : .d_version = EV_CURRENT,
250 : : };
251 : 78 : Elf_Data conv =
252 : : {
253 : : .d_type = ELF_T_WORD,
254 : 39 : .d_buf = rawdata->d_buf + rawdata->d_size - sizeof *crc,
255 : : .d_size = sizeof *crc,
256 : : .d_version = EV_CURRENT,
257 : : };
258 : :
259 : : GElf_Ehdr ehdr_mem;
260 : 39 : GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
261 [ + - ]: 39 : if (ehdr == NULL)
262 : : return NULL;
263 : :
264 : 39 : Elf_Data *d = gelf_xlatetom (elf, &crcdata, &conv, ehdr->e_ident[EI_DATA]);
265 [ + - ]: 39 : if (d == NULL)
266 : : return NULL;
267 [ - + ]: 39 : assert (d == &crcdata);
268 : :
269 : 65 : return rawdata->d_buf;
270 : : }
271 : :
272 : : /* If the main file might have been prelinked, then we need to
273 : : discover the correct synchronization address between the main and
274 : : debug files. Because of prelink's section juggling, we cannot rely
275 : : on the address_sync computed from PT_LOAD segments (see open_elf).
276 : :
277 : : We will attempt to discover a synchronization address based on the
278 : : section headers instead. But finding a section address that is
279 : : safe to use requires identifying which sections are SHT_PROGBITS.
280 : : We can do that in the main file, but in the debug file all the
281 : : allocated sections have been transformed into SHT_NOBITS so we have
282 : : lost the means to match them up correctly.
283 : :
284 : : The only method left to us is to decode the .gnu.prelink_undo
285 : : section in the prelinked main file. This shows what the sections
286 : : looked like before prelink juggled them--when they still had a
287 : : direct correspondence to the debug file. */
288 : : static Dwfl_Error
289 : 31 : find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
290 : : {
291 : : /* The magic section is only identified by name. */
292 : : size_t shstrndx;
293 [ + - ]: 31 : if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)
294 : : return DWFL_E_LIBELF;
295 : :
296 : : Elf_Scn *scn = NULL;
297 [ + + ]: 734 : while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
298 : : {
299 : : GElf_Shdr shdr_mem;
300 : 718 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
301 [ + - ]: 718 : if (unlikely (shdr == NULL))
302 : : return DWFL_E_LIBELF;
303 [ + + ]: 718 : if (shdr->sh_type == SHT_PROGBITS
304 [ + + ]: 374 : && !(shdr->sh_flags & SHF_ALLOC)
305 [ + - ]: 67 : && shdr->sh_name != 0)
306 : : {
307 : 67 : const char *secname = elf_strptr (mod->main.elf, shstrndx,
308 : : shdr->sh_name);
309 [ + - ]: 67 : if (unlikely (secname == NULL))
310 : : return DWFL_E_LIBELF;
311 [ + + ]: 718 : if (!strcmp (secname, ".gnu.prelink_undo"))
312 : : break;
313 : : }
314 : : }
315 : :
316 [ + + ]: 31 : if (scn == NULL)
317 : : /* There was no .gnu.prelink_undo section. */
318 : : return DWFL_E_NOERROR;
319 : :
320 : 15 : Elf_Data *undodata = elf_rawdata (scn, NULL);
321 [ + - ]: 15 : if (unlikely (undodata == NULL))
322 : : return DWFL_E_LIBELF;
323 : :
324 : : /* Decode the section. It consists of the original ehdr, phdrs,
325 : : and shdrs (but omits section 0). */
326 : :
327 : : union
328 : : {
329 : : Elf32_Ehdr e32;
330 : : Elf64_Ehdr e64;
331 : : } ehdr;
332 : 15 : Elf_Data dst =
333 : : {
334 : : .d_buf = &ehdr,
335 : : .d_size = sizeof ehdr,
336 : : .d_type = ELF_T_EHDR,
337 : : .d_version = EV_CURRENT
338 : : };
339 : 15 : Elf_Data src = *undodata;
340 : 15 : src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT);
341 : 15 : src.d_type = ELF_T_EHDR;
342 [ + - ]: 15 : if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
343 : : elf_getident (mod->main.elf, NULL)[EI_DATA])
344 : : == NULL))
345 : : return DWFL_E_LIBELF;
346 : :
347 : 15 : size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT);
348 : 15 : size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT);
349 : :
350 : : uint_fast16_t phnum;
351 : : uint_fast16_t shnum;
352 [ + + ]: 15 : if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
353 : : {
354 [ + - ]: 4 : if (ehdr.e32.e_shentsize != shentsize
355 [ + - ]: 4 : || ehdr.e32.e_phentsize != phentsize)
356 : : return DWFL_E_BAD_PRELINK;
357 : 4 : phnum = ehdr.e32.e_phnum;
358 : 4 : shnum = ehdr.e32.e_shnum;
359 : : }
360 : : else
361 : : {
362 [ + - ]: 11 : if (ehdr.e64.e_shentsize != shentsize
363 [ + - ]: 11 : || ehdr.e64.e_phentsize != phentsize)
364 : : return DWFL_E_BAD_PRELINK;
365 : 11 : phnum = ehdr.e64.e_phnum;
366 : 11 : shnum = ehdr.e64.e_shnum;
367 : : }
368 : :
369 : : /* Since prelink does not store the zeroth section header in the undo
370 : : section, it cannot support SHN_XINDEX encoding. */
371 [ + - ]: 15 : if (unlikely (shnum >= SHN_LORESERVE)
372 [ + - ]: 15 : || unlikely (undodata->d_size != (src.d_size
373 : : + phnum * phentsize
374 : : + (shnum - 1) * shentsize)))
375 : : return DWFL_E_BAD_PRELINK;
376 : :
377 : : /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections. (Most
378 : : every file will have some SHT_PROGBITS sections, but it's possible to
379 : : have one with nothing but .bss, i.e. SHT_NOBITS.) The special sections
380 : : that can be moved around have different sh_type values--except for
381 : : .interp, the section that became the PT_INTERP segment. So we exclude
382 : : the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr.
383 : : For this reason, we must examine the phdrs first to find PT_INTERP. */
384 : :
385 : 15 : GElf_Addr main_interp = 0;
386 : : {
387 : : size_t main_phnum;
388 [ + - ]: 15 : if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum)))
389 : : return DWFL_E_LIBELF;
390 [ + + ]: 65 : for (size_t i = 0; i < main_phnum; ++i)
391 : : {
392 : : GElf_Phdr phdr;
393 [ - + ]: 58 : if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL))
394 : : return DWFL_E_LIBELF;
395 [ + + ]: 58 : if (phdr.p_type == PT_INTERP)
396 : : {
397 : 8 : main_interp = phdr.p_vaddr;
398 : : break;
399 : : }
400 : : }
401 : : }
402 : :
403 : 15 : src.d_buf += src.d_size;
404 : 15 : src.d_type = ELF_T_PHDR;
405 : 15 : src.d_size = phnum * phentsize;
406 : :
407 : 15 : GElf_Addr undo_interp = 0;
408 : : {
409 : 30 : union
410 : : {
411 : 15 : Elf32_Phdr p32[phnum];
412 : 15 : Elf64_Phdr p64[phnum];
413 : 15 : } phdr;
414 : 15 : dst.d_buf = &phdr;
415 : 15 : dst.d_size = sizeof phdr;
416 [ - + ]: 15 : if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
417 : : ehdr.e32.e_ident[EI_DATA]) == NULL))
418 : : return DWFL_E_LIBELF;
419 [ + + ]: 15 : if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
420 : : {
421 [ + + ]: 16 : for (uint_fast16_t i = 0; i < phnum; ++i)
422 [ + + ]: 14 : if (phdr.p32[i].p_type == PT_INTERP)
423 : : {
424 : 2 : undo_interp = phdr.p32[i].p_vaddr;
425 : : break;
426 : : }
427 : : }
428 : : else
429 : : {
430 [ + + ]: 49 : for (uint_fast16_t i = 0; i < phnum; ++i)
431 [ + + ]: 44 : if (phdr.p64[i].p_type == PT_INTERP)
432 : : {
433 : 6 : undo_interp = phdr.p64[i].p_vaddr;
434 : : break;
435 : : }
436 : : }
437 : : }
438 : :
439 [ + - ]: 15 : if (unlikely ((main_interp == 0) != (undo_interp == 0)))
440 : : return DWFL_E_BAD_PRELINK;
441 : :
442 : 15 : src.d_buf += src.d_size;
443 : 15 : src.d_type = ELF_T_SHDR;
444 : 15 : src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
445 : :
446 : 30 : union
447 : : {
448 : 15 : Elf32_Shdr s32[shnum - 1];
449 : 15 : Elf64_Shdr s64[shnum - 1];
450 : 15 : } shdr;
451 : 15 : dst.d_buf = &shdr;
452 : 15 : dst.d_size = sizeof shdr;
453 [ + - ]: 15 : if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
454 : : ehdr.e32.e_ident[EI_DATA]) == NULL))
455 : : return DWFL_E_LIBELF;
456 : :
457 : : /* Now we can look at the original section headers of the main file
458 : : before it was prelinked. First we'll apply our method to the main
459 : : file sections as they are after prelinking, to calculate the
460 : : synchronization address of the main file. Then we'll apply that
461 : : same method to the saved section headers, to calculate the matching
462 : : synchronization address of the debug file.
463 : :
464 : : The method is to consider SHF_ALLOC sections that are either
465 : : SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr
466 : : matches the PT_INTERP p_vaddr. The special sections that can be
467 : : moved by prelink have other types, except for .interp (which
468 : : becomes PT_INTERP). The "real" sections cannot move as such, but
469 : : .bss can be split into .dynbss and .bss, with the total memory
470 : : image remaining the same but being spread across the two sections.
471 : : So we consider the highest section end, which still matches up. */
472 : :
473 : : GElf_Addr highest;
474 : :
475 : : inline void consider_shdr (GElf_Addr interp,
476 : : GElf_Word sh_type,
477 : : GElf_Xword sh_flags,
478 : : GElf_Addr sh_addr,
479 : : GElf_Xword sh_size)
480 : : {
481 [ + + ][ + + ]: 860 : if ((sh_flags & SHF_ALLOC)
[ + + ]
482 [ + + ][ + + ]: 711 : && ((sh_type == SHT_PROGBITS && sh_addr != interp)
[ + + ]
483 [ + + ][ + + ]: 372 : || sh_type == SHT_NOBITS))
[ + + ]
484 : : {
485 : 367 : const GElf_Addr sh_end = sh_addr + sh_size;
486 [ + - ][ + - ]: 634 : if (sh_end > highest)
[ + - ]
487 : : highest = sh_end;
488 : : }
489 : : }
490 : :
491 : : highest = 0;
492 : : scn = NULL;
493 [ + + ]: 467 : while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
494 : : {
495 : : GElf_Shdr sh_mem;
496 : 452 : GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem);
497 [ - + ]: 452 : if (unlikely (sh == NULL))
498 : : return DWFL_E_LIBELF;
499 : 452 : consider_shdr (main_interp, sh->sh_type, sh->sh_flags,
500 : : sh->sh_addr, sh->sh_size);
501 : : }
502 [ + - ]: 15 : if (highest > mod->main.vaddr)
503 : : {
504 : 15 : mod->main.address_sync = highest;
505 : :
506 : : highest = 0;
507 [ + + ]: 15 : if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
508 [ + + ]: 98 : for (size_t i = 0; i < shnum - 1; ++i)
509 : 188 : consider_shdr (undo_interp, shdr.s32[i].sh_type, shdr.s32[i].sh_flags,
510 : 188 : shdr.s32[i].sh_addr, shdr.s32[i].sh_size);
511 : : else
512 [ + + ]: 325 : for (size_t i = 0; i < shnum - 1; ++i)
513 : 314 : consider_shdr (undo_interp, shdr.s64[i].sh_type, shdr.s64[i].sh_flags,
514 : : shdr.s64[i].sh_addr, shdr.s64[i].sh_size);
515 : :
516 [ + - ]: 15 : if (highest > file->vaddr)
517 : 31 : file->address_sync = highest;
518 : : else
519 : : return DWFL_E_BAD_PRELINK;
520 : : }
521 : :
522 : : return DWFL_E_NOERROR;
523 : : }
524 : :
525 : : /* Find the separate debuginfo file for this module and open libelf on it.
526 : : When we return success, MOD->debug is set up. */
527 : : static Dwfl_Error
528 : 83 : find_debuginfo (Dwfl_Module *mod)
529 : : {
530 [ + + ]: 83 : if (mod->debug.elf != NULL)
531 : : return DWFL_E_NOERROR;
532 : :
533 : 65 : GElf_Word debuglink_crc = 0;
534 : 65 : const char *debuglink_file = find_debuglink (mod->main.elf, &debuglink_crc);
535 : :
536 : 65 : mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
537 : 65 : mod->main.name,
538 : : debuglink_file,
539 : : debuglink_crc,
540 : : &mod->debug.name);
541 : 65 : Dwfl_Error result = open_elf (mod, &mod->debug);
542 [ + + ][ + + ]: 65 : if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0)
543 : 83 : result = find_prelink_address_sync (mod, &mod->debug);
544 : : return result;
545 : : }
546 : :
547 : :
548 : : /* Try to find a symbol table in FILE.
549 : : Returns DWFL_E_NOERROR if a proper one is found.
550 : : Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM. */
551 : : static Dwfl_Error
552 : 109 : load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
553 : : Elf_Scn **symscn, Elf_Scn **xndxscn,
554 : : size_t *syments, int *first_global, GElf_Word *strshndx)
555 : : {
556 : 109 : bool symtab = false;
557 : 109 : Elf_Scn *scn = NULL;
558 [ + + ]: 3234 : while ((scn = elf_nextscn (file->elf, scn)) != NULL)
559 : : {
560 : 3125 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
561 [ + - ]: 3125 : if (shdr != NULL)
562 [ + + - + ]: 3125 : switch (shdr->sh_type)
563 : : {
564 : : case SHT_SYMTAB:
565 : 83 : symtab = true;
566 : 83 : *symscn = scn;
567 : 83 : *symfile = file;
568 : 83 : *strshndx = shdr->sh_link;
569 : 83 : *syments = shdr->sh_size / shdr->sh_entsize;
570 : 83 : *first_global = shdr->sh_info;
571 [ + - ]: 83 : if (*xndxscn != NULL)
572 : : return DWFL_E_NOERROR;
573 : : break;
574 : :
575 : : case SHT_DYNSYM:
576 [ + - ]: 61 : if (symtab)
577 : : break;
578 : : /* Use this if need be, but keep looking for SHT_SYMTAB. */
579 : 61 : *symscn = scn;
580 : 61 : *symfile = file;
581 : 61 : *strshndx = shdr->sh_link;
582 : 61 : *syments = shdr->sh_size / shdr->sh_entsize;
583 : 61 : *first_global = shdr->sh_info;
584 : 61 : break;
585 : :
586 : : case SHT_SYMTAB_SHNDX:
587 : 0 : *xndxscn = scn;
588 [ # # ]: 3125 : if (symtab)
589 : : return DWFL_E_NOERROR;
590 : : break;
591 : :
592 : : default:
593 : : break;
594 : : }
595 : : }
596 : :
597 [ + + ]: 109 : if (symtab)
598 : : /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */
599 : : return DWFL_E_NOERROR;
600 : :
601 : : /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
602 : : We might have found an SHT_DYNSYM and set *SYMSCN et al though. */
603 : 26 : *xndxscn = NULL;
604 : 109 : return DWFL_E_NO_SYMTAB;
605 : : }
606 : :
607 : :
608 : : /* Translate addresses into file offsets.
609 : : OFFS[*] start out zero and remain zero if unresolved. */
610 : : static void
611 : 2 : find_offsets (Elf *elf, size_t phnum, size_t n,
612 : : GElf_Addr addrs[n], GElf_Off offs[n])
613 : : {
614 : 2 : size_t unsolved = n;
615 [ + + ]: 12 : for (size_t i = 0; i < phnum; ++i)
616 : : {
617 : : GElf_Phdr phdr_mem;
618 : 10 : GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
619 [ + - ][ + + ]: 10 : if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
[ + - ]
620 [ + + ]: 20 : for (size_t j = 0; j < n; ++j)
621 [ + + ]: 16 : if (offs[j] == 0
622 [ + + ]: 10 : && addrs[j] >= phdr->p_vaddr
623 [ + - ]: 6 : && addrs[j] - phdr->p_vaddr < phdr->p_filesz)
624 : : {
625 : 6 : offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset;
626 [ + - ]: 6 : if (--unsolved == 0)
627 : : break;
628 : : }
629 : : }
630 : 2 : }
631 : :
632 : : /* Try to find a dynamic symbol table via phdrs. */
633 : : static void
634 : 2 : find_dynsym (Dwfl_Module *mod)
635 : : {
636 : : GElf_Ehdr ehdr_mem;
637 : 2 : GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
638 : :
639 : : size_t phnum;
640 [ + - ]: 2 : if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0))
641 : : return;
642 : :
643 [ + - ]: 8 : for (size_t i = 0; i < phnum; ++i)
644 : : {
645 : : GElf_Phdr phdr_mem;
646 : 6 : GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
647 [ + - ]: 6 : if (phdr == NULL)
648 : : break;
649 : :
650 [ + + ]: 6 : if (phdr->p_type == PT_DYNAMIC)
651 : : {
652 : : /* Examine the dynamic section for the pointers we need. */
653 : :
654 : 2 : Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
655 : 2 : phdr->p_offset, phdr->p_filesz,
656 : : ELF_T_DYN);
657 [ - + ]: 2 : if (data == NULL)
658 : 0 : continue;
659 : :
660 : : enum
661 : : {
662 : : i_symtab,
663 : : i_strtab,
664 : : i_hash,
665 : : i_gnu_hash,
666 : : i_max
667 : : };
668 : 2 : GElf_Addr addrs[i_max] = { 0, };
669 : 2 : GElf_Xword strsz = 0;
670 : 2 : size_t n = data->d_size / gelf_fsize (mod->main.elf,
671 : : ELF_T_DYN, 1, EV_CURRENT);
672 [ + - ]: 32 : for (size_t j = 0; j < n; ++j)
673 : : {
674 : : GElf_Dyn dyn_mem;
675 : 30 : GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
676 [ + - ]: 30 : if (dyn != NULL)
677 [ + - + + : 30 : switch (dyn->d_tag)
+ + + ]
678 : : {
679 : : case DT_SYMTAB:
680 : 2 : addrs[i_symtab] = dyn->d_un.d_ptr;
681 : 2 : continue;
682 : :
683 : : case DT_HASH:
684 : 0 : addrs[i_hash] = dyn->d_un.d_ptr;
685 : 0 : continue;
686 : :
687 : : case DT_GNU_HASH:
688 : 2 : addrs[i_gnu_hash] = dyn->d_un.d_ptr;
689 : 2 : continue;
690 : :
691 : : case DT_STRTAB:
692 : 2 : addrs[i_strtab] = dyn->d_un.d_ptr;
693 : 2 : continue;
694 : :
695 : : case DT_STRSZ:
696 : 2 : strsz = dyn->d_un.d_val;
697 : 2 : continue;
698 : :
699 : : default:
700 : 20 : continue;
701 : :
702 : : case DT_NULL:
703 : : break;
704 : : }
705 : : break;
706 : : }
707 : :
708 : : /* Translate pointers into file offsets. */
709 : 2 : GElf_Off offs[i_max] = { 0, };
710 : 2 : find_offsets (mod->main.elf, phnum, i_max, addrs, offs);
711 : :
712 : : /* Figure out the size of the symbol table. */
713 [ - + ]: 2 : if (offs[i_hash] != 0)
714 : : {
715 : : /* In the original format, .hash says the size of .dynsym. */
716 : :
717 [ # # ][ # # ]: 0 : size_t entsz = SH_ENTSIZE_HASH (ehdr);
[ # # ]
718 [ # # ]: 0 : data = elf_getdata_rawchunk (mod->main.elf,
719 : 0 : offs[i_hash] + entsz, entsz,
720 : : entsz == 4 ? ELF_T_WORD
721 : : : ELF_T_XWORD);
722 [ # # ]: 0 : if (data != NULL)
723 : 0 : mod->syments = (entsz == 4
724 : 0 : ? *(const GElf_Word *) data->d_buf
725 [ # # ]: 0 : : *(const GElf_Xword *) data->d_buf);
726 : : }
727 [ + - ][ + - ]: 2 : if (offs[i_gnu_hash] != 0 && mod->syments == 0)
728 : : {
729 : : /* In the new format, we can derive it with some work. */
730 : :
731 : : const struct
732 : : {
733 : : Elf32_Word nbuckets;
734 : : Elf32_Word symndx;
735 : : Elf32_Word maskwords;
736 : : Elf32_Word shift2;
737 : : } *header;
738 : :
739 : 2 : data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
740 : : sizeof *header, ELF_T_WORD);
741 [ + - ]: 2 : if (data != NULL)
742 : : {
743 : 2 : header = data->d_buf;
744 : 2 : Elf32_Word nbuckets = header->nbuckets;
745 : 2 : Elf32_Word symndx = header->symndx;
746 : 4 : GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
747 : 2 : + (gelf_getclass (mod->main.elf)
748 : : * sizeof (Elf32_Word)
749 : 2 : * header->maskwords));
750 : :
751 : 2 : data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
752 : : nbuckets * sizeof (Elf32_Word),
753 : : ELF_T_WORD);
754 [ + + ]: 2 : if (data != NULL && symndx < nbuckets)
755 : : {
756 : 1 : const Elf32_Word *const buckets = data->d_buf;
757 : 1 : Elf32_Word maxndx = symndx;
758 [ + + ]: 4 : for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
759 [ + + ]: 3 : if (buckets[bucket] > maxndx)
760 : 1 : maxndx = buckets[bucket];
761 : :
762 : 1 : GElf_Off hasharr_at = (buckets_at
763 : : + nbuckets * sizeof (Elf32_Word));
764 : 1 : hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
765 : : do
766 : : {
767 : 1 : data = elf_getdata_rawchunk (mod->main.elf,
768 : : hasharr_at,
769 : : sizeof (Elf32_Word),
770 : : ELF_T_WORD);
771 [ + - ]: 1 : if (data != NULL
772 [ + - ]: 1 : && (*(const Elf32_Word *) data->d_buf & 1u))
773 : : {
774 : 1 : mod->syments = maxndx + 1;
775 : 1 : break;
776 : : }
777 : 0 : ++maxndx;
778 : 0 : hasharr_at += sizeof (Elf32_Word);
779 [ # # ]: 0 : } while (data != NULL);
780 : : }
781 : : }
782 : : }
783 [ + - ][ + + ]: 2 : if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
784 : 1 : mod->syments = ((offs[i_strtab] - offs[i_symtab])
785 : 1 : / gelf_fsize (mod->main.elf,
786 : : ELF_T_SYM, 1, EV_CURRENT));
787 : :
788 [ + - ]: 2 : if (mod->syments > 0)
789 : : {
790 : 2 : mod->symdata = elf_getdata_rawchunk (mod->main.elf,
791 : 2 : offs[i_symtab],
792 : : gelf_fsize (mod->main.elf,
793 : : ELF_T_SYM,
794 : : mod->syments,
795 : : EV_CURRENT),
796 : : ELF_T_SYM);
797 [ + - ]: 2 : if (mod->symdata != NULL)
798 : : {
799 : 2 : mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
800 : 2 : offs[i_strtab],
801 : : strsz,
802 : : ELF_T_BYTE);
803 [ - + ]: 2 : if (mod->symstrdata == NULL)
804 : 0 : mod->symdata = NULL;
805 : : }
806 [ - + ]: 2 : if (mod->symdata == NULL)
807 : 0 : mod->symerr = DWFL_E (LIBELF, elf_errno ());
808 : : else
809 : : {
810 : 2 : mod->symfile = &mod->main;
811 : 6 : mod->symerr = DWFL_E_NOERROR;
812 : : }
813 : : return;
814 : : }
815 : : }
816 : : }
817 : : }
818 : :
819 : : /* Try to find the auxiliary symbol table embedded in the main elf file
820 : : section .gnu_debugdata. Only matters if the symbol information comes
821 : : from the main file dynsym. No harm done if not found. */
822 : : static void
823 : 6 : find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
824 : : Elf_Scn **aux_symscn __attribute__ ((unused)),
825 : : Elf_Scn **aux_xndxscn __attribute__ ((unused)),
826 : : GElf_Word *aux_strshndx __attribute__ ((unused)))
827 : : {
828 : : /* Since a .gnu_debugdata section is compressed using lzma don't do
829 : : anything unless we have support for that. */
830 : : #if USE_LZMA
831 : 6 : Elf *elf = mod->main.elf;
832 : :
833 : : size_t shstrndx;
834 [ + - ]: 6 : if (elf_getshdrstrndx (elf, &shstrndx) < 0)
835 : : return;
836 : :
837 : : Elf_Scn *scn = NULL;
838 [ + + ]: 79 : while ((scn = elf_nextscn (elf, scn)) != NULL)
839 : : {
840 : : GElf_Shdr shdr_mem;
841 : 75 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
842 [ + - ]: 75 : if (shdr == NULL)
843 : : return;
844 : :
845 : 75 : const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
846 [ + - ]: 75 : if (name == NULL)
847 : : return;
848 : :
849 [ + + ]: 75 : if (!strcmp (name, ".gnu_debugdata"))
850 : : break;
851 : : }
852 : :
853 [ + + ]: 6 : if (scn == NULL)
854 : : return;
855 : :
856 : : /* Found the .gnu_debugdata section. Uncompress the lzma image and
857 : : turn it into an ELF image. */
858 : 2 : Elf_Data *rawdata = elf_rawdata (scn, NULL);
859 [ + - ]: 2 : if (rawdata == NULL)
860 : : return;
861 : :
862 : : Dwfl_Error error;
863 : 2 : void *buffer = NULL;
864 : 2 : size_t size = 0;
865 : 2 : error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size,
866 : : &buffer, &size);
867 [ + - ]: 2 : if (error == DWFL_E_NOERROR)
868 : : {
869 [ - + ]: 2 : if (unlikely (size == 0))
870 : 0 : free (buffer);
871 : : else
872 : : {
873 : 2 : mod->aux_sym.elf = elf_memory (buffer, size);
874 [ - + ]: 2 : if (mod->aux_sym.elf == NULL)
875 : 0 : free (buffer);
876 : : else
877 : : {
878 : 2 : mod->aux_sym.fd = -1;
879 : 2 : mod->aux_sym.elf->flags |= ELF_F_MALLOCED;
880 [ + - ]: 2 : if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR)
881 : : return;
882 : : /* Don't trust the phdrs in the minisymtab elf file to be
883 : : setup correctly. The address_sync is equal to the main
884 : : file it is embedded in at first. The shdrs are setup
885 : : OK to make find_prelink_address_sync () do the right
886 : : thing if necessary though. */
887 : 2 : mod->aux_sym.address_sync = mod->main.address_sync;
888 [ + - ]: 2 : if (mod->aux_sym.address_sync != 0)
889 : : {
890 : 2 : error = find_prelink_address_sync (mod, &mod->aux_sym);
891 [ + - ]: 2 : if (error != DWFL_E_NOERROR)
892 : : {
893 : 0 : elf_end (mod->aux_sym.elf);
894 : 0 : mod->aux_sym.elf = NULL;
895 : : return;
896 : : }
897 : : }
898 : :
899 : : /* So far, so good. Get minisymtab table data and cache it. */
900 : : bool minisymtab = false;
901 : : scn = NULL;
902 [ + + ]: 37 : while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL)
903 : : {
904 : 35 : GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
905 [ + - ]: 35 : if (shdr != NULL)
906 [ + - + ]: 35 : switch (shdr->sh_type)
907 : : {
908 : : case SHT_SYMTAB:
909 : 2 : minisymtab = true;
910 : 2 : *aux_symscn = scn;
911 : 2 : *aux_strshndx = shdr->sh_link;
912 : 2 : mod->aux_syments = shdr->sh_size / shdr->sh_entsize;
913 : 2 : mod->aux_first_global = shdr->sh_info;
914 [ + - ]: 2 : if (*aux_xndxscn != NULL)
915 : : return;
916 : : break;
917 : :
918 : : case SHT_SYMTAB_SHNDX:
919 : 0 : *aux_xndxscn = scn;
920 [ # # ]: 35 : if (minisymtab)
921 : : return;
922 : : break;
923 : :
924 : : default:
925 : : break;
926 : : }
927 : : }
928 : :
929 [ - + ]: 2 : if (minisymtab)
930 : : /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */
931 : : return;
932 : :
933 : : /* We found no SHT_SYMTAB, so everything else is bogus. */
934 : 0 : *aux_xndxscn = NULL;
935 : 0 : *aux_strshndx = 0;
936 : 0 : mod->aux_syments = 0;
937 : 0 : elf_end (mod->aux_sym.elf);
938 : 0 : mod->aux_sym.elf = NULL;
939 : : return;
940 : : }
941 : : }
942 : : }
943 : : else
944 : 6 : free (buffer);
945 : : #endif
946 : : }
947 : :
948 : : /* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */
949 : : static void
950 : 661577 : find_symtab (Dwfl_Module *mod)
951 : : {
952 [ + + ][ + + ]: 661577 : if (mod->symdata != NULL || mod->aux_symdata != NULL /* Already done. */
953 [ + + ]: 93 : || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */
954 : : return;
955 : :
956 : 91 : __libdwfl_getelf (mod);
957 : 91 : mod->symerr = mod->elferr;
958 [ + + ]: 91 : if (mod->symerr != DWFL_E_NOERROR)
959 : : return;
960 : :
961 : : /* First see if the main ELF file has the debugging information. */
962 : 89 : Elf_Scn *symscn = NULL, *xndxscn = NULL;
963 : 89 : Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL;
964 : 89 : GElf_Word strshndx, aux_strshndx = 0;
965 : 89 : mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
966 : : &xndxscn, &mod->syments, &mod->first_global,
967 : : &strshndx);
968 [ + + - ]: 89 : switch (mod->symerr)
969 : : {
970 : : default:
971 : : return;
972 : :
973 : : case DWFL_E_NOERROR:
974 : : break;
975 : :
976 : : case DWFL_E_NO_SYMTAB:
977 : : /* Now we have to look for a separate debuginfo file. */
978 : 26 : mod->symerr = find_debuginfo (mod);
979 [ + + - ]: 26 : switch (mod->symerr)
980 : : {
981 : : default:
982 : : return;
983 : :
984 : : case DWFL_E_NOERROR:
985 : 20 : mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
986 : : &xndxscn, &mod->syments,
987 : : &mod->first_global, &strshndx);
988 : 20 : break;
989 : :
990 : : case DWFL_E_CB: /* The find_debuginfo hook failed. */
991 : 6 : mod->symerr = DWFL_E_NO_SYMTAB;
992 : 6 : break;
993 : : }
994 : :
995 [ + + - ]: 26 : switch (mod->symerr)
996 : : {
997 : : default:
998 : : return;
999 : :
1000 : : case DWFL_E_NOERROR:
1001 : : break;
1002 : :
1003 : : case DWFL_E_NO_SYMTAB:
1004 : : /* There might be an auxiliary table. */
1005 : 6 : find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx);
1006 : :
1007 [ + + ]: 6 : if (symscn != NULL)
1008 : : {
1009 : : /* We still have the dynamic symbol table. */
1010 : 3 : mod->symerr = DWFL_E_NOERROR;
1011 : 3 : break;
1012 : : }
1013 : :
1014 [ + + ]: 3 : if (aux_symscn != NULL)
1015 : : {
1016 : : /* We still have the auxiliary symbol table. */
1017 : 1 : mod->symerr = DWFL_E_NOERROR;
1018 : 1 : goto aux_cache;
1019 : : }
1020 : :
1021 : : /* Last ditch, look for dynamic symbols without section headers. */
1022 : 2 : find_dynsym (mod);
1023 : : return;
1024 : : }
1025 : : break;
1026 : : }
1027 : :
1028 : : /* This does some sanity checks on the string table section. */
1029 [ - + ]: 86 : if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
1030 : : {
1031 : : elferr:
1032 : 0 : mod->symerr = DWFL_E (LIBELF, elf_errno ());
1033 : 0 : goto aux_cleanup;
1034 : : }
1035 : :
1036 : : /* Cache the data; MOD->syments and MOD->first_global were set above. */
1037 : :
1038 : 86 : mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
1039 : : NULL);
1040 [ - + ]: 86 : if (mod->symstrdata == NULL)
1041 : : goto elferr;
1042 : :
1043 [ + - ]: 86 : if (xndxscn == NULL)
1044 : 86 : mod->symxndxdata = NULL;
1045 : : else
1046 : : {
1047 : 0 : mod->symxndxdata = elf_getdata (xndxscn, NULL);
1048 [ # # ]: 0 : if (mod->symxndxdata == NULL)
1049 : : goto elferr;
1050 : : }
1051 : :
1052 : 86 : mod->symdata = elf_getdata (symscn, NULL);
1053 [ - + ]: 86 : if (mod->symdata == NULL)
1054 : : goto elferr;
1055 : :
1056 : : /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym. */
1057 [ + + ]: 86 : if (aux_symscn != NULL)
1058 : : {
1059 : : aux_cache:
1060 : : /* This does some sanity checks on the string table section. */
1061 [ - + ]: 2 : if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL)
1062 : : {
1063 : : aux_cleanup:
1064 : 0 : mod->aux_syments = 0;
1065 : 0 : elf_end (mod->aux_sym.elf);
1066 : 0 : mod->aux_sym.elf = NULL;
1067 : : return;
1068 : : }
1069 : :
1070 : 2 : mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf,
1071 : : aux_strshndx),
1072 : : NULL);
1073 [ - + ]: 2 : if (mod->aux_symstrdata == NULL)
1074 : : goto aux_cleanup;
1075 : :
1076 [ + - ]: 2 : if (aux_xndxscn == NULL)
1077 : 2 : mod->aux_symxndxdata = NULL;
1078 : : else
1079 : : {
1080 : 0 : mod->aux_symxndxdata = elf_getdata (xndxscn, NULL);
1081 [ # # ]: 0 : if (mod->aux_symxndxdata == NULL)
1082 : : goto aux_cleanup;
1083 : : }
1084 : :
1085 : 2 : mod->aux_symdata = elf_getdata (aux_symscn, NULL);
1086 [ - + ]: 661577 : if (mod->aux_symdata == NULL)
1087 : : goto aux_cleanup;
1088 : : }
1089 : : }
1090 : :
1091 : :
1092 : : /* Try to open a libebl backend for MOD. */
1093 : : Dwfl_Error
1094 : : internal_function
1095 : 61 : __libdwfl_module_getebl (Dwfl_Module *mod)
1096 : : {
1097 [ + + ]: 61 : if (mod->ebl == NULL)
1098 : : {
1099 : 58 : __libdwfl_getelf (mod);
1100 [ + - ]: 58 : if (mod->elferr != DWFL_E_NOERROR)
1101 : : return mod->elferr;
1102 : :
1103 : 58 : mod->ebl = ebl_openbackend (mod->main.elf);
1104 [ + - ]: 61 : if (mod->ebl == NULL)
1105 : : return DWFL_E_LIBEBL;
1106 : : }
1107 : : return DWFL_E_NOERROR;
1108 : : }
1109 : :
1110 : : /* Try to start up libdw on DEBUGFILE. */
1111 : : static Dwfl_Error
1112 : 5161 : load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
1113 : : {
1114 [ + + ][ + + ]: 5161 : if (mod->e_type == ET_REL && !debugfile->relocated)
1115 : : {
1116 : 10 : const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
1117 : :
1118 : : /* The debugging sections have to be relocated. */
1119 [ + - ]: 10 : if (cb->section_address == NULL)
1120 : : return DWFL_E_NOREL;
1121 : :
1122 : 10 : Dwfl_Error error = __libdwfl_module_getebl (mod);
1123 [ + - ]: 10 : if (error != DWFL_E_NOERROR)
1124 : : return error;
1125 : :
1126 : 10 : find_symtab (mod);
1127 : 10 : Dwfl_Error result = mod->symerr;
1128 [ + - ]: 10 : if (result == DWFL_E_NOERROR)
1129 : 10 : result = __libdwfl_relocate (mod, debugfile->elf, true);
1130 [ + - ]: 10 : if (result != DWFL_E_NOERROR)
1131 : : return result;
1132 : :
1133 : : /* Don't keep the file descriptors around. */
1134 [ - + ][ # # ]: 10 : if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
1135 : : {
1136 : 0 : close (mod->main.fd);
1137 : 0 : mod->main.fd = -1;
1138 : : }
1139 [ + + ][ + - ]: 10 : if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
1140 : : {
1141 : 1 : close (debugfile->fd);
1142 : 1 : debugfile->fd = -1;
1143 : : }
1144 : : }
1145 : :
1146 : 5161 : mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
1147 [ + + ]: 5161 : if (mod->dw == NULL)
1148 : : {
1149 : 58 : int err = INTUSE(dwarf_errno) ();
1150 [ + + ]: 58 : return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
1151 : : }
1152 : :
1153 : : /* Until we have iterated through all CU's, we might do lazy lookups. */
1154 : 5103 : mod->lazycu = 1;
1155 : :
1156 : 5161 : return DWFL_E_NOERROR;
1157 : : }
1158 : :
1159 : : /* Try to start up libdw on either the main file or the debuginfo file. */
1160 : : static void
1161 : 5232 : find_dw (Dwfl_Module *mod)
1162 : : {
1163 [ + + ]: 5232 : if (mod->dw != NULL /* Already done. */
1164 [ + + ]: 5203 : || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */
1165 : : return;
1166 : :
1167 : 5140 : __libdwfl_getelf (mod);
1168 : 5140 : mod->dwerr = mod->elferr;
1169 [ + + ]: 5140 : if (mod->dwerr != DWFL_E_NOERROR)
1170 : : return;
1171 : :
1172 : : /* First see if the main ELF file has the debugging information. */
1173 : 5133 : mod->dwerr = load_dw (mod, &mod->main);
1174 [ + + + ]: 5133 : switch (mod->dwerr)
1175 : : {
1176 : : case DWFL_E_NOERROR:
1177 : 5075 : mod->debug.elf = mod->main.elf;
1178 : 5075 : mod->debug.address_sync = mod->main.address_sync;
1179 : 5075 : return;
1180 : :
1181 : : case DWFL_E_NO_DWARF:
1182 : : break;
1183 : :
1184 : : default:
1185 : : goto canonicalize;
1186 : : }
1187 : :
1188 : : /* Now we have to look for a separate debuginfo file. */
1189 : 57 : mod->dwerr = find_debuginfo (mod);
1190 [ + + - ]: 57 : switch (mod->dwerr)
1191 : : {
1192 : : case DWFL_E_NOERROR:
1193 : 28 : mod->dwerr = load_dw (mod, &mod->debug);
1194 : 28 : break;
1195 : :
1196 : : case DWFL_E_CB: /* The find_debuginfo hook failed. */
1197 : 29 : mod->dwerr = DWFL_E_NO_DWARF;
1198 : 29 : return;
1199 : :
1200 : : default:
1201 : : break;
1202 : : }
1203 : :
1204 : : canonicalize:
1205 : 5232 : mod->dwerr = __libdwfl_canon_error (mod->dwerr);
1206 : : }
1207 : :
1208 : : Dwarf *
1209 : 5232 : dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
1210 : : {
1211 [ + - ]: 5232 : if (mod == NULL)
1212 : : return NULL;
1213 : :
1214 : 5232 : find_dw (mod);
1215 [ + + ]: 5232 : if (mod->dwerr == DWFL_E_NOERROR)
1216 : : {
1217 : : /* If dwfl_module_getelf was used previously, then partial apply
1218 : : relocation to miscellaneous sections in the debug file too. */
1219 [ + + ]: 5132 : if (mod->e_type == ET_REL
1220 [ + + ][ + - ]: 16 : && mod->main.relocated && ! mod->debug.relocated)
1221 : : {
1222 : 10 : mod->debug.relocated = true;
1223 [ - + ]: 10 : if (mod->debug.elf != mod->main.elf)
1224 : 0 : (void) __libdwfl_relocate (mod, mod->debug.elf, false);
1225 : : }
1226 : :
1227 : 5132 : *bias = dwfl_adjusted_dwarf_addr (mod, 0);
1228 : 5132 : return mod->dw;
1229 : : }
1230 : :
1231 : 100 : __libdwfl_seterrno (mod->dwerr);
1232 : 5232 : return NULL;
1233 : : }
1234 : : INTDEF (dwfl_module_getdwarf)
1235 : :
1236 : : int
1237 : 661567 : dwfl_module_getsymtab (Dwfl_Module *mod)
1238 : : {
1239 [ + - ]: 661567 : if (mod == NULL)
1240 : : return -1;
1241 : :
1242 : 661567 : find_symtab (mod);
1243 [ + + ]: 661567 : if (mod->symerr == DWFL_E_NOERROR)
1244 : : /* We will skip the auxiliary zero entry if there is another one. */
1245 [ + + ]: 1323126 : return (mod->syments + mod->aux_syments
1246 [ + + ]: 661563 : - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0));
1247 : :
1248 : 4 : __libdwfl_seterrno (mod->symerr);
1249 : 661567 : return -1;
1250 : : }
1251 : 15400 : INTDEF (dwfl_module_getsymtab)
|