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