Branch data Line data Source code
1 : : /* Core file handling.
2 : : Copyright (C) 2008-2010, 2013, 2015 Red Hat, Inc.
3 : : Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #include <config.h>
31 : : #include "../libelf/libelfP.h" /* For NOTE_ALIGN. */
32 : : #undef _
33 : : #include "libdwflP.h"
34 : : #include <gelf.h>
35 : :
36 : : #include <unistd.h>
37 : : #include <endian.h>
38 : : #include <byteswap.h>
39 : : #include "system.h"
40 : :
41 : :
42 : : /* On failure return, we update *NEXT to point back at OFFSET. */
43 : : static inline Elf *
44 : 0 : do_fail (int error, off_t *next, off_t offset)
45 : : {
46 : 0 : if (next != NULL)
47 : 0 : *next = offset;
48 : : //__libelf_seterrno (error);
49 : 0 : __libdwfl_seterrno (DWFL_E (LIBELF, error));
50 : 0 : return NULL;
51 : : }
52 : :
53 : : #define fail(error) do_fail (error, next, offset)
54 : :
55 : : /* This is a prototype of what a new libelf interface might be.
56 : : This implementation is pessimal for non-mmap cases and should
57 : : be replaced by more diddling inside libelf internals. */
58 : : static Elf *
59 : 35 : elf_begin_rand (Elf *parent, off_t offset, off_t size, off_t *next)
60 : : {
61 [ + - ]: 35 : if (parent == NULL)
62 : : return NULL;
63 : :
64 : 70 : off_t min = (parent->kind == ELF_K_ELF ?
65 : 35 : (parent->class == ELFCLASS32
66 : : ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
67 [ + - + + : 35 : : parent->kind == ELF_K_AR ? SARMAG
- - ]
68 : : : 0);
69 : :
70 [ + - ]: 35 : if (unlikely (offset < min)
71 [ - + ]: 35 : || unlikely (offset >= (off_t) parent->maximum_size))
72 [ # # ]: 0 : return fail (ELF_E_RANGE);
73 : :
74 : : /* For an archive, fetch just the size field
75 : : from the archive header to override SIZE. */
76 [ - + ]: 35 : if (parent->kind == ELF_K_AR)
77 : : {
78 : 0 : struct ar_hdr h = { .ar_size = "" };
79 : :
80 [ # # ]: 0 : if (unlikely (parent->maximum_size - offset < sizeof h))
81 [ # # ]: 0 : return fail (ELF_E_RANGE);
82 : :
83 [ # # ]: 0 : if (parent->map_address != NULL)
84 : 0 : memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
85 : : sizeof h.ar_size);
86 [ # # ]: 0 : else if (unlikely (pread_retry (parent->fildes,
87 : : h.ar_size, sizeof (h.ar_size),
88 : : parent->start_offset + offset
89 : : + offsetof (struct ar_hdr, ar_size))
90 : : != sizeof (h.ar_size)))
91 [ # # ]: 0 : return fail (ELF_E_READ_ERROR);
92 : :
93 : 0 : offset += sizeof h;
94 : :
95 : 0 : char *endp;
96 : 0 : size = strtoll (h.ar_size, &endp, 10);
97 [ # # ]: 0 : if (unlikely (endp == h.ar_size)
98 [ # # ]: 0 : || unlikely ((off_t) parent->maximum_size - offset < size))
99 [ # # ]: 0 : return fail (ELF_E_INVALID_ARCHIVE);
100 : : }
101 : :
102 [ - + ]: 35 : if (unlikely ((off_t) parent->maximum_size - offset < size))
103 [ # # ]: 0 : return fail (ELF_E_RANGE);
104 : :
105 : : /* Even if we fail at this point, update *NEXT to point past the file. */
106 [ - + ]: 35 : if (next != NULL)
107 : 0 : *next = offset + size;
108 : :
109 [ - + ]: 35 : if (unlikely (offset == 0)
110 [ # # ]: 0 : && unlikely (size == (off_t) parent->maximum_size))
111 : 0 : return elf_clone (parent, parent->cmd);
112 : :
113 : : /* Note the image is guaranteed live only as long as PARENT
114 : : lives. Using elf_memory is quite suboptimal if the whole
115 : : file is not mmap'd. We really should have something like
116 : : a generalization of the archive support. */
117 : 35 : Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
118 [ + - ]: 35 : if (data == NULL)
119 : : return NULL;
120 [ - + ]: 35 : assert ((off_t) data->d_size == size);
121 : 35 : return elf_memory (data->d_buf, size);
122 : : }
123 : :
124 : :
125 : : int
126 : 35 : dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
127 : : {
128 [ + - ]: 35 : if (unlikely (dwfl == NULL))
129 : : return -1;
130 : :
131 : 35 : int result = 0;
132 : :
133 [ + - ]: 35 : if (notes != NULL)
134 : 35 : notes->p_type = PT_NULL;
135 : :
136 [ + + ]: 717 : for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
137 : : {
138 : 682 : GElf_Phdr phdr_mem;
139 : 682 : GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
140 [ - + ]: 682 : if (unlikely (phdr == NULL))
141 : : {
142 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
143 : 0 : return -1;
144 : : }
145 [ + + - ]: 682 : switch (phdr->p_type)
146 : : {
147 : 647 : case PT_LOAD:
148 : 647 : result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
149 : 647 : break;
150 : :
151 : 35 : case PT_NOTE:
152 [ + - ]: 35 : if (notes != NULL)
153 : : {
154 : 35 : *notes = *phdr;
155 : 35 : notes = NULL;
156 : : }
157 : : break;
158 : : }
159 : 682 : }
160 : :
161 : : return result;
162 : : }
163 : :
164 : : /* Never read more than this much without mmap. */
165 : : #define MAX_EAGER_COST 8192
166 : :
167 : : /* Dwfl_Module_Callback passed to and called by dwfl_segment_report_module
168 : : to read in a segment as ELF image directly if possible or indicate an
169 : : attempt must be made to read in the while segment right now. */
170 : : static bool
171 : 116 : core_file_read_eagerly (Dwfl_Module *mod,
172 : : void **userdata __attribute__ ((unused)),
173 : : const char *name __attribute__ ((unused)),
174 : : Dwarf_Addr start __attribute__ ((unused)),
175 : : void **buffer, size_t *buffer_available,
176 : : GElf_Off cost, GElf_Off worthwhile,
177 : : GElf_Off whole,
178 : : GElf_Off contiguous __attribute__ ((unused)),
179 : : void *arg, Elf **elfp)
180 : : {
181 : 116 : Elf *core = arg;
182 : :
183 : : /* The available buffer is often the whole segment when the core file
184 : : was mmap'd if used together with the dwfl_elf_phdr_memory_callback.
185 : : Which means that if it is complete we can just construct the whole
186 : : ELF image right now without having to read in anything more. */
187 [ + + ]: 116 : if (whole <= *buffer_available)
188 : : {
189 : : /* All there ever was, we already have on hand. */
190 : :
191 [ - + ]: 35 : if (core->map_address == NULL)
192 : : {
193 : : /* We already malloc'd the buffer. */
194 : 0 : *elfp = elf_memory (*buffer, whole);
195 [ # # ]: 0 : if (unlikely (*elfp == NULL))
196 : : return false;
197 : :
198 : 0 : (*elfp)->flags |= ELF_F_MALLOCED;
199 : 0 : *buffer = NULL;
200 : 0 : *buffer_available = 0;
201 : 0 : return true;
202 : : }
203 : :
204 : : /* We can use the image inside the core file directly. */
205 : 35 : *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
206 : 35 : *buffer = NULL;
207 : 35 : *buffer_available = 0;
208 : 35 : return *elfp != NULL;
209 : : }
210 : :
211 : : /* We don't have the whole file. Which either means the core file
212 : : wasn't mmap'd, but needs to still be read in, or that the segment
213 : : is truncated. Figure out if this is better than nothing. */
214 : :
215 [ + + ]: 81 : if (worthwhile == 0)
216 : : /* Caller doesn't think so. */
217 : : return false;
218 : :
219 : : /*
220 : : XXX would like to fall back to partial file via memory
221 : : when build id find_elf fails
222 : : also, link_map name may give file name from disk better than partial here
223 : : requires find_elf hook re-doing the magic to fall back if no file found
224 : : */
225 : :
226 [ + + - + ]: 31 : if (whole > MAX_EAGER_COST && mod->build_id_len > 0)
227 : : /* We can't cheaply read the whole file here, so we'd
228 : : be using a partial file. But there is a build ID that could
229 : : help us find the whole file, which might be more useful than
230 : : what we have. We'll just rely on that. */
231 : : return false;
232 : :
233 : : /* The file is either small (most likely the vdso) or big and incomplete,
234 : : but we don't have a build-id. */
235 : :
236 [ - + ]: 2 : if (core->map_address != NULL)
237 : : /* It's cheap to get, so get it. */
238 : : return true;
239 : :
240 : : /* Only use it if there isn't too much to be read. */
241 : 0 : return cost <= MAX_EAGER_COST;
242 : : }
243 : :
244 : : static inline void
245 : 1183 : update_end (GElf_Phdr *pphdr, const GElf_Off align,
246 : : GElf_Off *pend, GElf_Addr *pend_vaddr)
247 : : {
248 : 1183 : *pend = (pphdr->p_offset + pphdr->p_filesz + align - 1) & -align;
249 : 1183 : *pend_vaddr = (pphdr->p_vaddr + pphdr->p_memsz + align - 1) & -align;
250 : 1183 : }
251 : :
252 : : /* Use following contiguous segments to get towards SIZE. */
253 : : static inline bool
254 : 2258 : do_more (size_t size, GElf_Phdr *pphdr, const GElf_Off align,
255 : : Elf *elf, GElf_Off start, int *pndx,
256 : : GElf_Off *pend, GElf_Addr *pend_vaddr)
257 : : {
258 [ + + + + ]: 4903 : while (*pend <= start || *pend - start < size)
259 : : {
260 [ + + ]: 1145 : if (pphdr->p_filesz < pphdr->p_memsz)
261 : : /* This segment is truncated, so no following one helps us. */
262 : : return false;
263 : :
264 [ + - ]: 940 : if (unlikely (gelf_getphdr (elf, (*pndx)++, pphdr) == NULL))
265 : : return false;
266 : :
267 [ + - ]: 940 : if (pphdr->p_type == PT_LOAD)
268 : : {
269 [ + - ]: 940 : if (pphdr->p_offset > *pend
270 [ + + ]: 940 : || pphdr->p_vaddr > *pend_vaddr)
271 : : /* It's discontiguous! */
272 : : return false;
273 : :
274 : 387 : update_end (pphdr, align, pend, pend_vaddr);
275 : : }
276 : : }
277 : : return true;
278 : : }
279 : :
280 : : #define more(size) do_more (size, &phdr, align, elf, start, &ndx, &end, &end_vaddr)
281 : :
282 : : bool
283 : 1488 : dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
284 : : void **buffer, size_t *buffer_available,
285 : : GElf_Addr vaddr,
286 : : size_t minread,
287 : : void *arg)
288 : : {
289 : 1488 : Elf *elf = arg;
290 : :
291 [ + + ]: 1488 : if (ndx == -1)
292 : : {
293 : : /* Called for cleanup. */
294 [ - + ]: 692 : if (elf->map_address == NULL)
295 : 0 : free (*buffer);
296 : 692 : *buffer = NULL;
297 : 692 : *buffer_available = 0;
298 : 692 : return false;
299 : : }
300 : :
301 : 796 : const GElf_Off align = dwfl->segment_align ?: 1;
302 : 831 : GElf_Phdr phdr;
303 : :
304 : 831 : do
305 [ + - ]: 831 : if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
306 : : return false;
307 : 831 : while (phdr.p_type != PT_LOAD
308 [ + + - + ]: 831 : || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
309 : :
310 : 796 : GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset;
311 : 796 : GElf_Off end;
312 : 796 : GElf_Addr end_vaddr;
313 : :
314 : 796 : update_end (&phdr, align, &end, &end_vaddr);
315 : :
316 : : /* We need at least this much. */
317 [ + + ]: 796 : if (! more (minread))
318 : : return false;
319 : :
320 : : /* See how much more we can get of what the caller wants. */
321 : 731 : (void) more (*buffer_available);
322 : :
323 : : /* If it's already on hand anyway, use as much as there is. */
324 [ + - + - ]: 731 : if (elf->map_address != NULL && start < elf->maximum_size)
325 : 731 : (void) more (elf->maximum_size - start);
326 : :
327 : : /* Make sure we don't look past the end of the actual file,
328 : : even if the headers tell us to. */
329 [ - + ]: 731 : if (unlikely (end > elf->maximum_size))
330 : 0 : end = elf->maximum_size;
331 : :
332 : : /* If the file is too small, there is nothing at all to get. */
333 [ + - ]: 731 : if (unlikely (start >= end))
334 : : return false;
335 : :
336 [ + - ]: 731 : if (end - start < minread)
337 : : return false;
338 : :
339 [ + - ]: 731 : if (elf->map_address != NULL)
340 : : {
341 : 731 : void *contents = elf->map_address + elf->start_offset + start;
342 : 731 : size_t size = end - start;
343 : :
344 [ + + ]: 731 : if (minread == 0) /* String mode. */
345 : : {
346 : 70 : const void *eos = memchr (contents, '\0', size);
347 [ + - + - ]: 70 : if (unlikely (eos == NULL) || unlikely (eos == contents))
348 : : return false;
349 : 70 : size = eos + 1 - contents;
350 : : }
351 : :
352 [ + + ]: 731 : if (*buffer == NULL)
353 : : {
354 : 727 : *buffer = contents;
355 : 727 : *buffer_available = size;
356 : : }
357 : : else
358 : : {
359 : 4 : *buffer_available = MIN (size, *buffer_available);
360 : 4 : memcpy (*buffer, contents, *buffer_available);
361 : : }
362 : : }
363 : : else
364 : : {
365 : 0 : void *into = *buffer;
366 [ # # ]: 0 : if (*buffer == NULL)
367 : : {
368 [ # # ]: 0 : *buffer_available = MIN (minread ?: 512,
369 : : MAX (4096, MIN (end - start,
370 : : *buffer_available)));
371 : 0 : into = malloc (*buffer_available);
372 [ # # ]: 0 : if (unlikely (into == NULL))
373 : : {
374 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
375 : 0 : return false;
376 : : }
377 : : }
378 : :
379 : 0 : ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
380 [ # # ]: 0 : if (nread < (ssize_t) minread)
381 : : {
382 [ # # ]: 0 : if (into != *buffer)
383 : 0 : free (into);
384 [ # # ]: 0 : if (nread < 0)
385 : 0 : __libdwfl_seterrno (DWFL_E_ERRNO);
386 : 0 : return false;
387 : : }
388 : :
389 [ # # ]: 0 : if (minread == 0) /* String mode. */
390 : : {
391 : 0 : const void *eos = memchr (into, '\0', nread);
392 [ # # # # ]: 0 : if (unlikely (eos == NULL) || unlikely (eos == into))
393 : : {
394 [ # # ]: 0 : if (*buffer == NULL)
395 : 0 : free (into);
396 : 0 : return false;
397 : : }
398 : 0 : nread = eos + 1 - into;
399 : : }
400 : :
401 [ # # ]: 0 : if (*buffer == NULL)
402 : 0 : *buffer = into;
403 : 0 : *buffer_available = nread;
404 : : }
405 : :
406 : : return true;
407 : : }
408 : :
409 : : /* Free the contents of R_DEBUG_INFO without the R_DEBUG_INFO memory itself. */
410 : :
411 : : static void
412 : 35 : clear_r_debug_info (struct r_debug_info *r_debug_info)
413 : : {
414 [ + + ]: 148 : while (r_debug_info->module != NULL)
415 : : {
416 : 113 : struct r_debug_info_module *module = r_debug_info->module;
417 : 113 : r_debug_info->module = module->next;
418 : 113 : elf_end (module->elf);
419 [ - + ]: 113 : if (module->fd != -1)
420 : 0 : close (module->fd);
421 : 113 : free (module);
422 : : }
423 : 35 : }
424 : :
425 : : bool
426 : : internal_function
427 : 43 : __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp)
428 : : {
429 : 43 : size_t phnum;
430 [ + - ]: 43 : if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
431 : : return false;
432 [ + - ]: 205 : for (size_t i = 0; i < phnum; ++i)
433 : : {
434 : 205 : GElf_Phdr phdr_mem;
435 : 205 : GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
436 [ + - ]: 205 : if (unlikely (phdr == NULL))
437 : 43 : return false;
438 [ + + ]: 205 : if (phdr->p_type == PT_DYNAMIC)
439 : : {
440 : 43 : *vaddrp = phdr->p_vaddr;
441 : 43 : return true;
442 : : }
443 : : }
444 : : return false;
445 : : }
446 : :
447 : : NEW_VERSION (dwfl_core_file_report, ELFUTILS_0.158)
448 : : int
449 : 35 : dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
450 : : {
451 : 35 : size_t phnum;
452 [ - + ]: 35 : if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
453 : : {
454 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
455 : 0 : return -1;
456 : : }
457 : :
458 : 35 : bool cleanup_user_core = false;
459 [ - + ]: 35 : if (dwfl->user_core != NULL)
460 : 0 : free (dwfl->user_core->executable_for_core);
461 [ + + ]: 35 : if (executable == NULL)
462 : : {
463 [ - + ]: 4 : if (dwfl->user_core != NULL)
464 : 0 : dwfl->user_core->executable_for_core = NULL;
465 : : }
466 : : else
467 : : {
468 [ + - ]: 31 : if (dwfl->user_core == NULL)
469 : : {
470 : 31 : cleanup_user_core = true;
471 : 31 : dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
472 [ - + ]: 31 : if (dwfl->user_core == NULL)
473 : : {
474 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
475 : 0 : return -1;
476 : : }
477 : 31 : dwfl->user_core->fd = -1;
478 : : }
479 : 31 : dwfl->user_core->executable_for_core = strdup (executable);
480 [ - + ]: 31 : if (dwfl->user_core->executable_for_core == NULL)
481 : : {
482 [ # # ]: 0 : if (cleanup_user_core)
483 : : {
484 : 0 : free (dwfl->user_core);
485 : 0 : dwfl->user_core = NULL;
486 : : }
487 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
488 : 0 : return -1;
489 : : }
490 : : }
491 : :
492 : : /* First report each PT_LOAD segment. */
493 : 35 : GElf_Phdr notes_phdr;
494 : 35 : int ndx = dwfl_report_core_segments (dwfl, elf, phnum, ¬es_phdr);
495 [ - + ]: 35 : if (unlikely (ndx <= 0))
496 : : {
497 [ # # ]: 0 : if (cleanup_user_core)
498 : : {
499 : 0 : free (dwfl->user_core->executable_for_core);
500 : 0 : free (dwfl->user_core);
501 : 0 : dwfl->user_core = NULL;
502 : : }
503 : 0 : return ndx;
504 : : }
505 : :
506 : : /* Next, we should follow the chain from DT_DEBUG. */
507 : :
508 : 35 : const void *auxv = NULL;
509 : 35 : const void *note_file = NULL;
510 : 35 : size_t auxv_size = 0;
511 : 35 : size_t note_file_size = 0;
512 [ + - ]: 35 : if (likely (notes_phdr.p_type == PT_NOTE))
513 : : {
514 : : /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
515 : :
516 : 35 : Elf_Data *notes = elf_getdata_rawchunk (elf,
517 : 35 : notes_phdr.p_offset,
518 : : notes_phdr.p_filesz,
519 [ + - ]: 35 : (notes_phdr.p_align == 8
520 : : ? ELF_T_NHDR8
521 : : : ELF_T_NHDR));
522 [ + - ]: 35 : if (likely (notes != NULL))
523 : : {
524 : : size_t pos = 0;
525 : : GElf_Nhdr nhdr;
526 : : size_t name_pos;
527 : : size_t desc_pos;
528 [ + + ]: 282 : while ((pos = gelf_getnote (notes, pos, &nhdr,
529 : : &name_pos, &desc_pos)) > 0)
530 [ + + ]: 247 : if (nhdr.n_namesz == sizeof "CORE"
531 [ + - ]: 196 : && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
532 : : {
533 [ + + ]: 196 : if (nhdr.n_type == NT_AUXV)
534 : : {
535 : 35 : auxv = notes->d_buf + desc_pos;
536 : 35 : auxv_size = nhdr.n_descsz;
537 : : }
538 [ + + ]: 196 : if (nhdr.n_type == NT_FILE)
539 : : {
540 : 23 : note_file = notes->d_buf + desc_pos;
541 : 23 : note_file_size = nhdr.n_descsz;
542 : : }
543 : : }
544 : : }
545 : : }
546 : :
547 : : /* Now we have NT_AUXV contents. From here on this processing could be
548 : : used for a live process with auxv read from /proc. */
549 : :
550 : 35 : struct r_debug_info r_debug_info;
551 : 35 : memset (&r_debug_info, 0, sizeof r_debug_info);
552 : 35 : int retval = dwfl_link_map_report (dwfl, auxv, auxv_size,
553 : : dwfl_elf_phdr_memory_callback, elf,
554 : : &r_debug_info);
555 : 35 : int listed = retval > 0 ? retval : 0;
556 : :
557 : : /* Now sniff segment contents for modules hinted by information gathered
558 : : from DT_DEBUG. */
559 : :
560 : 35 : ndx = 0;
561 : 420 : do
562 : : {
563 : 420 : int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
564 : : &dwfl_elf_phdr_memory_callback, elf,
565 : : core_file_read_eagerly, elf,
566 : : elf->maximum_size,
567 : : note_file, note_file_size,
568 : : &r_debug_info);
569 [ - + ]: 420 : if (unlikely (seg < 0))
570 : : {
571 : 0 : clear_r_debug_info (&r_debug_info);
572 : 0 : return seg;
573 : : }
574 [ + + ]: 420 : if (seg > ndx)
575 : : {
576 : 117 : ndx = seg;
577 : 117 : ++listed;
578 : : }
579 : : else
580 : 303 : ++ndx;
581 : : }
582 [ + + ]: 420 : while (ndx < (int) phnum);
583 : :
584 : : /* Now report the modules from dwfl_link_map_report which were not filtered
585 : : out by dwfl_segment_report_module. */
586 : :
587 : 35 : Dwfl_Module **lastmodp = &dwfl->modulelist;
588 [ + + ]: 152 : while (*lastmodp != NULL)
589 : 117 : lastmodp = &(*lastmodp)->next;
590 : 35 : for (struct r_debug_info_module *module = r_debug_info.module;
591 [ + + ]: 148 : module != NULL; module = module->next)
592 : : {
593 [ + + ]: 113 : if (module->elf == NULL)
594 : 92 : continue;
595 : 21 : GElf_Addr file_dynamic_vaddr;
596 [ - + ]: 21 : if (! __libdwfl_dynamic_vaddr_get (module->elf, &file_dynamic_vaddr))
597 : 0 : continue;
598 : 21 : Dwfl_Module *mod;
599 : 21 : mod = __libdwfl_report_elf (dwfl, basename (module->name), module->name,
600 : : module->fd, module->elf,
601 : 21 : module->l_ld - file_dynamic_vaddr,
602 : : true, true);
603 [ - + ]: 21 : if (mod == NULL)
604 : 0 : continue;
605 : 21 : ++listed;
606 : 21 : module->elf = NULL;
607 : 21 : module->fd = -1;
608 : : /* Move this module to the end of the list, so that we end
609 : : up with a list in the same order as the link_map chain. */
610 [ - + ]: 21 : if (mod->next != NULL)
611 : : {
612 [ # # ]: 0 : if (*lastmodp != mod)
613 : : {
614 : : lastmodp = &dwfl->modulelist;
615 [ # # ]: 0 : while (*lastmodp != mod)
616 : 0 : lastmodp = &(*lastmodp)->next;
617 : : }
618 : 0 : *lastmodp = mod->next;
619 : 0 : mod->next = NULL;
620 [ # # ]: 0 : while (*lastmodp != NULL)
621 : 0 : lastmodp = &(*lastmodp)->next;
622 : 0 : *lastmodp = mod;
623 : : }
624 : 21 : lastmodp = &mod->next;
625 : : }
626 : :
627 : 35 : clear_r_debug_info (&r_debug_info);
628 : :
629 : : /* We return the number of modules we found if we found any.
630 : : If we found none, we return -1 instead of 0 if there was an
631 : : error rather than just nothing found. */
632 [ + - ]: 35 : return listed > 0 ? listed : retval;
633 : : }
634 : : NEW_INTDEF (dwfl_core_file_report)
635 : :
636 : : #ifdef SYMBOL_VERSIONING
637 : : int _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf);
638 : : COMPAT_VERSION_NEWPROTO (dwfl_core_file_report, ELFUTILS_0.146,
639 : : without_executable)
640 : :
641 : : int
642 : : _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
643 : : {
644 : : return dwfl_core_file_report (dwfl, elf, NULL);
645 : : }
646 : : #endif
|