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