2 Copyright (C) 2008-2010 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
5 Red Hat elfutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
9 Red Hat elfutils is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with Red Hat elfutils; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18 In addition, as a special exception, Red Hat, Inc. gives You the
19 additional right to link the code of Red Hat elfutils with code licensed
20 under any Open Source Initiative certified open source license
21 (http://www.opensource.org/licenses/index.php) which requires the
22 distribution of source code with any binary distribution and to
23 distribute linked combinations of the two. Non-GPL Code permitted under
24 this exception must only link to the code of Red Hat elfutils through
25 those well defined interfaces identified in the file named EXCEPTION
26 found in the source code files (the "Approved Interfaces"). The files
27 of Non-GPL Code may instantiate templates or use macros or inline
28 functions from the Approved Interfaces without causing the resulting
29 work to be covered by the GNU General Public License. Only Red Hat,
30 Inc. may make changes or additions to the list of Approved Interfaces.
31 Red Hat's grant of this exception is conditioned upon your not adding
32 any new exceptions. If you wish to add a new Approved Interface or
33 exception, please contact Red Hat. You must obey the GNU General Public
34 License in all respects for all of the Red Hat elfutils code and other
35 code used in conjunction with Red Hat elfutils except the Non-GPL Code
36 covered by this exception. If you modify this file, you may extend this
37 exception to your version of the file, but you are not obligated to do
38 so. If you do not wish to provide this exception without modification,
39 you must delete this exception statement from your version and license
40 this file solely under the GPL without exception.
42 Red Hat elfutils is an included package of the Open Invention Network.
43 An included package of the Open Invention Network is a package for which
44 Open Invention Network licensees cross-license their patents. No patent
45 license is granted, either expressly or impliedly, by designation as an
46 included package. Should you wish to participate in the Open Invention
47 Network licensing program, please visit www.openinventionnetwork.com
48 <http://www.openinventionnetwork.com>. */
51 #include "../libelf/libelfP.h" /* For NOTE_ALIGN. */
56 #include <sys/param.h>
63 /* This is a prototype of what a new libelf interface might be.
64 This implementation is pessimal for non-mmap cases and should
65 be replaced by more diddling inside libelf internals. */
67 elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next)
72 /* On failure return, we update *NEXT to point back at OFFSET. */
73 inline Elf *fail (int error)
77 //__libelf_seterrno (error);
78 __libdwfl_seterrno (DWFL_E (LIBELF, error));
82 loff_t min = (parent->kind == ELF_K_ELF ?
83 (parent->class == ELFCLASS32
84 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
85 : parent->kind == ELF_K_AR ? SARMAG
88 if (unlikely (offset < min)
89 || unlikely (offset >= (loff_t) parent->maximum_size))
90 return fail (ELF_E_RANGE);
92 /* For an archive, fetch just the size field
93 from the archive header to override SIZE. */
94 if (parent->kind == ELF_K_AR)
96 struct ar_hdr h = { .ar_size = "" };
98 if (unlikely (parent->maximum_size - offset < sizeof h))
99 return fail (ELF_E_RANGE);
101 if (parent->map_address != NULL)
102 memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
104 else if (unlikely (pread_retry (parent->fildes,
105 h.ar_size, sizeof (h.ar_size),
106 parent->start_offset + offset
107 + offsetof (struct ar_hdr, ar_size))
108 != sizeof (h.ar_size)))
109 return fail (ELF_E_READ_ERROR);
114 size = strtoll (h.ar_size, &endp, 10);
115 if (unlikely (endp == h.ar_size)
116 || unlikely ((loff_t) parent->maximum_size - offset < size))
117 return fail (ELF_E_INVALID_ARCHIVE);
120 if (unlikely ((loff_t) parent->maximum_size - offset < size))
121 return fail (ELF_E_RANGE);
123 /* Even if we fail at this point, update *NEXT to point past the file. */
125 *next = offset + size;
127 if (unlikely (offset == 0)
128 && unlikely (size == (loff_t) parent->maximum_size))
129 return elf_clone (parent, parent->cmd);
131 /* Note the image is guaranteed live only as long as PARENT
132 lives. Using elf_memory is quite suboptimal if the whole
133 file is not mmap'd. We really should have something like
134 a generalization of the archive support. */
135 Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
138 assert ((loff_t) data->d_size == size);
139 return elf_memory (data->d_buf, size);
144 dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
146 if (unlikely (dwfl == NULL))
152 notes->p_type = PT_NULL;
154 for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
157 GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
158 if (unlikely (phdr == NULL))
160 __libdwfl_seterrno (DWFL_E_LIBELF);
163 switch (phdr->p_type)
166 result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
182 /* Never read more than this much without mmap. */
183 #define MAX_EAGER_COST 8192
186 core_file_read_eagerly (Dwfl_Module *mod,
187 void **userdata __attribute__ ((unused)),
188 const char *name __attribute__ ((unused)),
189 Dwarf_Addr start __attribute__ ((unused)),
190 void **buffer, size_t *buffer_available,
191 GElf_Off cost, GElf_Off worthwhile,
193 GElf_Off contiguous __attribute__ ((unused)),
194 void *arg, Elf **elfp)
198 if (whole <= *buffer_available)
200 /* All there ever was, we already have on hand. */
202 if (core->map_address == NULL)
204 /* We already malloc'd the buffer. */
205 *elfp = elf_memory (*buffer, whole);
206 if (unlikely (*elfp == NULL))
209 (*elfp)->flags |= ELF_F_MALLOCED;
211 *buffer_available = 0;
215 /* We can use the image inside the core file directly. */
216 *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
218 *buffer_available = 0;
219 return *elfp != NULL;
222 /* We don't have the whole file.
223 Figure out if this is better than nothing. */
226 /* Caller doesn't think so. */
230 XXX would like to fall back to partial file via memory
231 when build id find_elf fails
232 also, link_map name may give file name from disk better than partial here
233 requires find_elf hook re-doing the magic to fall back if no file found
236 if (mod->build_id_len > 0)
237 /* There is a build ID that could help us find the whole file,
238 which might be more useful than what we have.
239 We'll just rely on that. */
242 if (core->map_address != NULL)
243 /* It's cheap to get, so get it. */
246 /* Only use it if there isn't too much to be read. */
247 return cost <= MAX_EAGER_COST;
251 dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
252 void **buffer, size_t *buffer_available,
261 /* Called for cleanup. */
262 if (elf->map_address == NULL)
265 *buffer_available = 0;
269 const GElf_Off align = dwfl->segment_align ?: 1;
273 if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
275 while (phdr.p_type != PT_LOAD
276 || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
278 GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset;
282 inline void update_end ()
284 end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align;
285 end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align;
290 /* Use following contiguous segments to get towards SIZE. */
291 inline bool more (size_t size)
293 while (end <= start || end - start < size)
295 if (phdr.p_filesz < phdr.p_memsz)
296 /* This segment is truncated, so no following one helps us. */
299 if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
302 if (phdr.p_type == PT_LOAD)
304 if (phdr.p_offset > end
305 || phdr.p_vaddr > end_vaddr)
306 /* It's discontiguous! */
315 /* We need at least this much. */
316 if (! more (minread))
319 /* See how much more we can get of what the caller wants. */
320 (void) more (*buffer_available);
322 /* If it's already on hand anyway, use as much as there is. */
323 if (elf->map_address != NULL)
324 (void) more (elf->maximum_size - start);
326 /* Make sure we don't look past the end of the actual file,
327 even if the headers tell us to. */
328 if (unlikely (end > elf->maximum_size))
329 end = elf->maximum_size;
331 /* If the file is too small, there is nothing at all to get. */
332 if (unlikely (start >= end))
335 if (elf->map_address != NULL)
337 void *contents = elf->map_address + elf->start_offset + start;
338 size_t size = end - start;
340 if (minread == 0) /* String mode. */
342 const void *eos = memchr (contents, '\0', size);
343 if (unlikely (eos == NULL) || unlikely (eos == contents))
345 size = eos + 1 - contents;
351 *buffer_available = size;
355 *buffer_available = MIN (size, *buffer_available);
356 memcpy (*buffer, contents, *buffer_available);
361 void *into = *buffer;
364 *buffer_available = MIN (minread ?: 512,
365 MAX (4096, MIN (end - start,
366 *buffer_available)));
367 into = malloc (*buffer_available);
368 if (unlikely (into == NULL))
370 __libdwfl_seterrno (DWFL_E_NOMEM);
375 ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
376 if (nread < (ssize_t) minread)
381 __libdwfl_seterrno (DWFL_E_ERRNO);
385 if (minread == 0) /* String mode. */
387 const void *eos = memchr (into, '\0', nread);
388 if (unlikely (eos == NULL) || unlikely (eos == into))
394 nread = eos + 1 - into;
399 *buffer_available = nread;
406 dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
409 if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
411 __libdwfl_seterrno (DWFL_E_LIBELF);
415 /* First report each PT_LOAD segment. */
416 GElf_Phdr notes_phdr;
417 int ndx = dwfl_report_core_segments (dwfl, elf, phnum, ¬es_phdr);
418 if (unlikely (ndx <= 0))
421 /* Now sniff segment contents for modules. */
426 int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
427 &dwfl_elf_phdr_memory_callback, elf,
428 core_file_read_eagerly, elf);
429 if (unlikely (seg < 0))
439 while (ndx < (int) phnum);
441 /* Next, we should follow the chain from DT_DEBUG. */
443 const void *auxv = NULL;
444 size_t auxv_size = 0;
445 if (likely (notes_phdr.p_type == PT_NOTE))
447 /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
449 Elf_Data *notes = elf_getdata_rawchunk (elf,
453 if (likely (notes != NULL))
459 while ((pos = gelf_getnote (notes, pos, &nhdr,
460 &name_pos, &desc_pos)) > 0)
461 if (nhdr.n_type == NT_AUXV
462 && nhdr.n_namesz == sizeof "CORE"
463 && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
465 auxv = notes->d_buf + desc_pos;
466 auxv_size = nhdr.n_descsz;
472 /* Now we have NT_AUXV contents. From here on this processing could be
473 used for a live process with auxv read from /proc. */
475 int listed = dwfl_link_map_report (dwfl, auxv, auxv_size,
476 dwfl_elf_phdr_memory_callback, elf);
478 /* We return the number of modules we found if we found any.
479 If we found none, we return -1 instead of 0 if there was an
480 error rather than just nothing found. If link_map handling
481 failed, we still have the sniffed modules. */
482 return sniffed == 0 || listed > sniffed ? listed : sniffed;
484 INTDEF (dwfl_core_file_report)