addr2line: new option --symbols (or -S)
+libelf: new functions gelf_begin_embedded, gelf_rawnote,
+ gelf_getdata_memory, gelf_getdata_rawchunk, gelf_getdata_freedata,
+ gelf_getauxv, gelf_update_auxv; new Elf_Type value ELF_T_AUXV
+
+libdwfl: new functions dwfl_core_file_report, dwfl_core_file_find_elf;
+ dwfl_standard_argp supports new option --core-file;
+ support dynamic symbol tables found via phdrs
+
Version 0.128:
new program: unstrip
+2007-08-04 Roland McGrath <roland@redhat.com>
+
+ * libdw.map (ELFUTILS_0.131): Add dwfl_module_build_id,
+ dwfl_module_report_build_id, dwfl_build_id_find_elf,
+ dwfl_build_id_find_debuginfo.
+
+2007-04-19 Roland McGrath <roland@redhat.com>
+
+ * libdw.map (ELFUTILS_0.131): New set, inherits from ELFUTILS_0.130.
+ Add dwfl_register_map, dwfl_register_map_begin, dwfl_register_map_end,
+ dwfl_register_map_populate, dwfl_core_file_report,
+ dwfl_core_file_find_elf, dwfl_core_file_register_map,
+ dwfl_core_file_read_note.
+
2007-10-17 Roland McGrath <roland@redhat.com>
* libdw.h (__deprecated_attribute__): New macro.
local:
*;
} ELFUTILS_0.127;
+
+ELFUTILS_0.131 {
+ global:
+ dwfl_register_map;
+ dwfl_register_map_begin;
+ dwfl_register_map_end;
+ dwfl_register_map_populate;
+
+ dwfl_core_file_report;
+ dwfl_core_file_find_elf;
+ dwfl_core_file_register_map;
+ dwfl_core_file_read_note;
+
+ local:
+ *;
+} ELFUTILS_0.130;
+2007-08-04 Roland McGrath <roland@redhat.com>
+
+ * core-file.c (dwfl_core_file_report): Use dwfl_module_report_build_id.
+ (dwfl_core_file_find_elf): Use dwfl_build_id_find_elf.
+
+2007-05-03 Roland McGrath <roland@redhat.com>
+
+ * core-file.c (no_module_overlaps): Renamed to ...
+ (module_overlapping): ... here. Return pointer instead of bool.
+ Take new bool argument REORDER; if true, move found module to end.
+ (offset_from_addr): New function.
+ (string_from_offset): New function.
+ (string_from_memory): New function.
+ (getdata_core): New function.
+ (addr_from_memory): New function.
+ (report_link_map, report_r_debug, find_dt_debug): New functions.
+ (dwfl_core_file_report): Use string_from_offset for soname extraction.
+ Notice DT_DEBUG in found PT_DYNAMIC sections.
+ Failing that, look for it in modules previously reported explicitly.
+ Use report_r_debug to follow link_map list from DT_DEBUG.
+ (dwfl_find_elf_by_build_id): Free old *FILE_NAME before setting it.
+
+2007-04-29 Roland McGrath <roland@redhat.com>
+
+ * core-file.c (no_module_overlaps): New function.
+ (dwfl_core_file_report): Use it to exclude duplicate modules.
+
+ * dwfl_module.c (__libdwfl_module_free): Free MOD->cb_data.
+
+ * argp-std.c (corefile_callbacks): Variable removed.
+ (offline_callbacks): Use its .find_elf here.
+ (parse_opt): Permit -e and --core together.
+
+2007-04-08 Roland McGrath <roland@redhat.com>
+
+ * register-map.c: New file.
+ * core-file-register-map.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwfl.h (Dwfl_Register_Map): New opaque typedef.
+ Declare dwfl_register_map_* functions, dwfl_core_file_register_map,
+ and dwfl_core_file_read_note.
+ * libdwflP.h (struct Dwfl_Register_Map): New type.
+ (struct map_register): New type.
+
2007-10-23 Roland McGrath <roland@redhat.com>
* linux-kernel-modules.c (report_kernel_archive): Reorder the kernel
build_id_len, build_id_vaddr. Declare __libdwfl_find_build_id.
* dwfl_module.c (__libdwfl_module_free): Free MOD->build_id_bits.
- * dwfl_module_getdwarf.c (find_offsets): New function.
- (find_dynsym): New function, calls that.
- (find_symtab): Call it.
-
2007-09-11 Roland McGrath <roland@redhat.com>
* dwfl_module_addrsym.c: Prefer a later global symbol at the same
2007-03-12 Roland McGrath <roland@redhat.com>
+ * argp-std.c (OPT_COREFILE): New macro.
+ (corefile_callbacks): New const variable.
+ (parse_opt, options): Add --core option.
+
+ * core-file.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_core_file_report, dwfl_core_file_find_elf.
+ * libdwflP.h: Add INTDECLs.
+
+ * libdwflP.h (struct Dwfl): New member `cb_data'.
+ (struct Dwfl_Module): Likewise.
+
* dwfl_module.c (dwfl_report_begin_add): New function broken out of ...
(dwfl_report_begin): ... here. Call it.
* libdwfl.h: Declare it.
* offline.c: Comment typo fix.
+2007-03-10 Roland McGrath <roland@redhat.com>
+
+ * linux-proc-maps.c (find_sysinfo_ehdr): Rewritten to use
+ gelf_getdata_memory and gelf_getauxv.
+
2007-03-04 Roland McGrath <roland@redhat.com>
* linux-kernel-modules.c (KERNEL_MODNAME): New macro for "kernel".
argp-std.c find-debuginfo.c \
dwfl_build_id_find_elf.c \
dwfl_build_id_find_debuginfo.c \
- linux-kernel-modules.c linux-proc-maps.c \
+ dwfl_build_id_find_elf.c \
+ dwfl_build_id_find_debuginfo.c \
+ linux-kernel-modules.c linux-proc-maps.c core-file.c \
dwfl_addrmodule.c dwfl_addrdwarf.c \
cu.c dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
dwfl_module_addrdie.c dwfl_addrdie.c \
dwfl_module_getsym.c \
dwfl_module_addrname.c dwfl_module_addrsym.c \
dwfl_module_return_value_location.c \
- dwfl_module_register_names.c
+ dwfl_module_register_names.c \
+ register-map.c core-file-register-map.c
if MUDFLAP
#include <stdlib.h>
#include <assert.h>
#include <libintl.h>
+#include <fcntl.h>
+#include <unistd.h>
/* gettext helper macros. */
#define _(Str) dgettext ("elfutils", Str)
-#define OPT_DEBUGINFO 0x100
+#define OPT_DEBUGINFO 0x100
+#define OPT_COREFILE 0x101
static const struct argp_option options[] =
{
{ NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
{ "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
+ { "core", OPT_COREFILE, "COREFILE", 0,
+ N_("Find addresses from signatures found in COREFILE"), 0 },
{ "pid", 'p', "PID", 0,
N_("Find addresses in files mapped into process PID"), 0 },
{ "linux-process-map", 'M', "FILE", 0,
.debuginfo_path = &debuginfo_path,
.section_address = INTUSE(dwfl_offline_section_address),
+
+ /* We use this table for core files too. */
+ .find_elf = INTUSE(dwfl_core_file_find_elf),
};
static const Dwfl_Callbacks proc_callbacks =
else
{
toomany:
- argp_error (state,
- "%s", _("only one of -e, -p, -k, or -K allowed"));
+ argp_error (state, "%s",
+ _("only one of -e, -p, -k, -K, or --core allowed"));
return EINVAL;
}
}
{
FILE *f = fopen (arg, "r");
if (f == NULL)
+ nofile:
{
int code = errno;
argp_failure (state, EXIT_FAILURE, code,
goto toomany;
break;
+ case OPT_COREFILE:
+ {
+ Dwfl *dwfl = state->hook;
+ if (dwfl == NULL)
+ state->hook = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ /* Permit -e and --core together. */
+ else if (dwfl->callbacks != &offline_callbacks
+ || dwfl->cb_data != NULL)
+ goto toomany;
+
+ int fd = open64 (arg, O_RDONLY);
+ if (fd < 0)
+ goto nofile;
+
+ Elf *core = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+ if (core == NULL)
+ {
+ close (fd);
+ argp_failure (state, EXIT_FAILURE, 0,
+ _("cannot read ELF core file: %s"),
+ elf_errmsg (-1));
+ return EIO;
+ }
+
+ int result = INTUSE(dwfl_core_file_report) (dwfl, core);
+ if (result < 0)
+ {
+ elf_end (core);
+ close (fd);
+ return fail (dwfl, result, arg);
+ }
+
+ /* From now we leak FD and CORE. */
+
+ if (result == 0)
+ {
+ argp_failure (state, EXIT_FAILURE, 0,
+ _("No modules recognized in core file"));
+ return ENOENT;
+ }
+ }
+ break;
+
case 'k':
if (state->hook == NULL)
{
--- /dev/null
+/* Examine a core file for notes describing register data.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "libdwflP.h"
+
+#include <gelf.h>
+
+
+// XXX
+static inline bool
+ebl_core_note_p (Elf *core __attribute__ ((unused)),
+ const GElf_Nhdr *nhdr, const char *name)
+{
+ inline bool check (const char *core_name, size_t core_namesz)
+ {
+ if (nhdr->n_namesz == core_namesz)
+ return !memcmp (name, core_name, core_namesz);
+
+ /* Also cater to buggy old Linux kernels. */
+ if (nhdr->n_namesz == core_namesz - 1)
+ return !memcmp (name, core_name, core_namesz - 1);
+
+ return false;
+ }
+
+#define NAME1 "CORE"
+#define NAME2 "LINUX"
+
+ return check (NAME1, sizeof NAME1) || check (NAME2, sizeof NAME2);
+}
+
+
+/* We've found a PT_NOTE segment. Look at each note. */
+static inline int
+handle_note (Dwfl *dwfl, Elf *core, const GElf_Phdr *phdr,
+ Dwfl_Register_Map *map, int *setno,
+ GElf_Off *start, GElf_Off *end)
+{
+ Elf_Data *data = gelf_getdata_rawchunk (core, phdr->p_offset, phdr->p_filesz,
+ ELF_T_NHDR);
+ if (data == NULL)
+ return -1;
+
+ *start = phdr->p_offset;
+ *end = phdr->p_offset + data->d_size;
+
+ int result = 0;
+ size_t offset = 0;
+ GElf_Nhdr nhdr;
+ size_t name_offset;
+ size_t desc_offset;
+ while (offset < data->d_size
+ && (offset = gelf_getnote (data, offset,
+ &nhdr, &name_offset, &desc_offset)) > 0)
+ {
+ result = ebl_core_note_p (core, &nhdr, data->d_buf + name_offset);
+ if (result < 0)
+ break;
+
+ if (result == 0)
+ {
+ *start = phdr->p_offset + offset;
+ continue;
+ }
+
+ result = dwfl_register_map_populate (map, dwfl, *setno,
+ nhdr.n_type, 0, nhdr.n_descsz);
+ if (result < 0)
+ break;
+ if (result > 0)
+ ++*setno;
+ }
+
+ return result;
+}
+
+// XXX change this interface: return Elf_Data of notes?
+int
+dwfl_core_file_register_map (dwfl, map, offset, limit)
+ Dwfl *dwfl;
+ Dwfl_Register_Map **map;
+ GElf_Off *offset;
+ GElf_Off *limit;
+{
+ if (dwfl == NULL)
+ return -1;
+
+ Elf *core = dwfl->cb_data;
+
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
+ if (ehdr == NULL)
+ {
+ elf_error:
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+
+ *map = dwfl_register_map_begin ();
+
+ int setno = 0;
+ for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (core, i, &phdr_mem);
+ if (phdr == NULL)
+ goto elf_error;
+ if (phdr->p_type == PT_NOTE)
+ {
+ int result = handle_note (dwfl, core, phdr, *map,
+ &setno, offset, limit);
+ if (result < 0)
+ setno = -1;
+ if (result != 0)
+ break;
+ }
+ }
+
+ if (setno <= 0)
+ {
+ dwfl_register_map_end (*map);
+ *map = NULL;
+ }
+
+ return setno;
+}
+
+int
+dwfl_core_file_read_note (dwfl, map, offset, limit,
+ nsets, offsets, sizes,
+ ident_setno, ident_pos, ident_type,
+ new_offset, next, out_desc_offset)
+ Dwfl *dwfl;
+ Dwfl_Register_Map *map;
+ GElf_Off offset;
+ GElf_Off limit;
+ int nsets;
+ GElf_Off offsets[nsets];
+ GElf_Word sizes[nsets];
+ int *ident_setno;
+ GElf_Word *ident_pos;
+ Elf_Type *ident_type;
+ GElf_Off *new_offset;
+ GElf_Nhdr *next;
+ GElf_Off *out_desc_offset;
+{
+ if (dwfl == NULL || map == NULL || nsets <= map->ident_setno - 1)
+ return -1;
+
+ Elf *core = dwfl->cb_data;
+
+ memset (offsets, 0, nsets * sizeof offsets[0]);
+ memset (sizes, 0, nsets * sizeof sizes[0]);
+ *ident_setno = -1;
+ *ident_pos = 0;
+ *ident_type = ELF_T_NUM;
+
+ Elf_Data *data = gelf_getdata_rawchunk (core, offset, limit - offset,
+ ELF_T_NHDR);
+ if (data == NULL)
+ return -1;
+
+ int result = 0;
+ size_t pos = 0;
+ size_t name_offset;
+ size_t desc_offset;
+ while (pos < data->d_size
+ && (pos = gelf_getnote (data, pos,
+ next, &name_offset, &desc_offset)) > 0
+ && ebl_core_note_p (core, next, data->d_buf + name_offset))
+ {
+ int i;
+
+ for (i = 0; i < map->nsets; ++i)
+ if (map->types[i] == next->n_type)
+ break;
+ if (i == map->nsets)
+ break;
+
+ if (i == *ident_setno || (i < nsets && sizes[0] != 0))
+ {
+ /* This is a repeat set, must be the next thread. */
+ result = 1;
+ break;
+ }
+
+ if (likely (i < nsets))
+ {
+ offsets[i] = offset + desc_offset;
+ sizes[i] = next->n_descsz;
+ }
+
+ if (i == map->ident_setno - 1)
+ {
+ *ident_setno = i;
+ *ident_pos = map->ident_pos;
+ *ident_type = map->ident_type;
+ }
+ }
+
+ *out_desc_offset = offset + desc_offset;
+
+ if (offset == 0 && limit != 0)
+ return -1;
+
+ *new_offset = offset + pos;
+ return result;
+}
--- /dev/null
+/* Examine a core file to guess the modules used in the crashed process.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "libdwflP.h"
+
+#include <gelf.h>
+#include <inttypes.h>
+#include <alloca.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+
+/* Determine whether a module already reported in this reporting phase
+ overlaps START..END. If REORDER, move it to the end of the list
+ as dwfl_report_module on an existing module would do. */
+static Dwfl_Module *
+module_overlapping (Dwfl *dwfl, GElf_Addr start, GElf_Addr end, bool reorder)
+{
+ Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
+ for (Dwfl_Module *mod = *prevp; mod != NULL; mod = *(prevp = &mod->next))
+ if (! mod->gc)
+ {
+ if ((start >= mod->low_addr && start < mod->high_addr)
+ || (end >= mod->low_addr && end < mod->high_addr)
+ || (mod->low_addr >= start && mod->low_addr < end))
+ {
+ if (reorder)
+ {
+ *prevp = mod->next;
+ mod->next = *tailp;
+ *tailp = mod;
+ }
+ return mod;
+ }
+
+ tailp = &mod->next;
+ }
+
+ return NULL;
+}
+
+
+/* Collected ideas about each module, stored in Dwfl_Module.cb_data. */
+struct core_module_info
+{
+ GElf_Off offset; /* Start position in the core file. */
+ GElf_Word whole_size; /* Zero or size of whole image at offset. */
+ GElf_Addr l_name_vaddr; /* l_name file name from dynamic linker. */
+};
+
+
+static GElf_Off
+offset_from_addr (Elf *elf, GElf_Addr addr, GElf_Off *limit)
+{
+ // XXX optimize with binary search of cached merged regions
+
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return 0;
+
+ GElf_Addr end = 0;
+ GElf_Off offset = 0;
+ for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
+ if (phdr == NULL)
+ break;
+ if (phdr->p_type != PT_LOAD || phdr->p_vaddr + phdr->p_memsz <= addr)
+ continue;
+ if (offset == 0)
+ offset = addr - phdr->p_vaddr + phdr->p_offset;
+ else if ((phdr->p_vaddr & -phdr->p_align) > end)
+ break;
+ end = phdr->p_vaddr + phdr->p_filesz;
+ }
+
+ *limit = end - addr + offset;
+ return offset;
+}
+
+/* Do gelf_rawchunk to get a '\0'-terminated string at
+ the given offset in the core file. Ignore an empty string. */
+static char *
+string_from_offset (Elf *core, GElf_Off string_offset, GElf_Off limit)
+{
+ GElf_Off offset = string_offset;
+
+#define STRING_BUF_SIZE 64
+ while (offset < limit)
+ {
+ const size_t sample_size = MIN (limit - offset, STRING_BUF_SIZE);
+ char *sample = gelf_rawchunk (core, offset, sample_size);
+ if (sample == NULL)
+ break;
+ char *end = memchr (sample, '\0', sample_size);
+ if (end == NULL)
+ {
+ gelf_freechunk (core, sample);
+ offset += sample_size;
+ }
+ else if (offset == string_offset)
+ {
+ if (end != sample)
+ return sample;
+ /* It's the empty string. */
+ gelf_freechunk (core, sample);
+ return NULL;
+ }
+ else
+ {
+ gelf_freechunk (core, sample);
+ return gelf_rawchunk (core, string_offset,
+ (offset - string_offset) + (end - sample));
+ }
+ }
+
+ return NULL;
+}
+
+// XXX l_name can be in elided text (.interp), needs module-integrated read here
+/* Do gelf_rawchunk to get a '\0'-terminated string at
+ the given address in the core file memory image. */
+static char *
+string_from_memory (Elf *core, GElf_Addr addr)
+{
+ GElf_Off limit;
+ GElf_Off offset = offset_from_addr (core, addr, &limit);
+ return offset == 0 ? NULL : string_from_offset (core, offset, limit);
+}
+
+/* Do gelf_getdata_rawchunk given an address in the core file memory image. */
+static Elf_Data *
+getdata_core (Elf *core, GElf_Addr addr, GElf_Word size, Elf_Type type)
+{
+ GElf_Off limit;
+ GElf_Off offset = offset_from_addr (core, addr, &limit);
+ return (limit - offset < size ? NULL
+ : gelf_getdata_rawchunk (core, offset, size, type));
+}
+
+/* Fetch one address word from the core file memory image. */
+static GElf_Addr
+addr_from_memory (Elf *core, GElf_Addr addr)
+{
+ const size_t addrsize = gelf_fsize (core, ELF_T_ADDR, 1, EV_CURRENT);
+ Elf_Data *data = getdata_core (core, addr, addrsize, ELF_T_ADDR);
+ if (data == NULL)
+ return 0;
+ return (addrsize == 4
+ ? *(const Elf32_Addr *) data->d_buf
+ : *(const Elf64_Addr *) data->d_buf);
+}
+
+/* Process a struct link_map extracted from the core file.
+ Report a module if it describes one we can figure out. */
+static int
+report_link_map (int result, Elf *core, Dwfl *dwfl,
+ GElf_Addr l_addr, GElf_Addr l_name, GElf_Addr l_ld)
+{
+ /* The l_ld address is a runtime address inside the module,
+ so we can use that alone to see if we already know this module.
+ This moves the one found to the end of the order as a side effect. */
+ Dwfl_Module *mod = module_overlapping (dwfl, l_ld, l_ld + 1, true);
+
+ if (mod == NULL)
+ {
+ /* We have to find the file's phdrs to compute along with l_addr
+ what its runtime address boundaries are. */
+
+ char *file_name = string_from_memory (core, l_name);
+ if (file_name != NULL)
+ {
+ mod = INTUSE(dwfl_report_elf) (dwfl, basename (file_name),
+ file_name, -1, l_addr);
+ if (mod != NULL)
+ result = 1;
+ gelf_freechunk (core, file_name);
+ }
+
+ return result;
+ }
+
+ if (mod->cb_data != NULL)
+ {
+ /* This is a module we recognized before from the core contents. */
+ struct core_module_info *info = mod->cb_data;
+ info->l_name_vaddr = l_name;
+ if (mod->name[0] == '[')
+ {
+ /* We gave it a boring synthetic name.
+ Use the basename of its l_name string instead. */
+ char *chunk = string_from_memory (core, info->l_name_vaddr);
+ if (chunk != NULL)
+ {
+ char *newname = strdup (basename (chunk));
+ if (newname != NULL)
+ {
+ free (mod->name);
+ mod->name = newname;
+ }
+ gelf_freechunk (core, chunk);
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Call report_link_map for each struct link_map in the linked list at r_map
+ in the struct r_debug at R_DEBUG_VADDR. */
+static int
+report_r_debug (int result, Elf *core, Dwfl *dwfl, GElf_Addr r_debug_vaddr)
+{
+ const size_t addrsize = gelf_fsize (core, ELF_T_ADDR, 1, EV_CURRENT);
+
+ /* Skip r_version, to aligned r_map field. */
+ GElf_Addr next = addr_from_memory (core, r_debug_vaddr + addrsize);
+
+ while (result >= 0 && next != 0)
+ {
+ Elf_Data *data = getdata_core (core, next, addrsize * 4, ELF_T_ADDR);
+ if (unlikely (data == NULL))
+ result = -1;
+ else
+ {
+ GElf_Addr addr;
+ GElf_Addr name;
+ GElf_Addr ld;
+
+ if (addrsize == 4)
+ {
+ const Elf32_Addr *map = data->d_buf;
+ addr = map[0];
+ name = map[1];
+ ld = map[2];
+ next = map[3];
+ }
+ else
+ {
+ const Elf64_Addr *map = data->d_buf;
+ addr = map[0];
+ name = map[1];
+ ld = map[2];
+ next = map[3];
+ }
+
+ result = report_link_map (result, core, dwfl, addr, name, ld);
+ }
+ }
+
+ return result;
+}
+
+/* Find the vaddr of the DT_DEBUG's d_ptr. This is the memory address
+ where &r_debug was written at runtime. */
+static GElf_Addr
+find_dt_debug (Elf *elf, GElf_Addr bias)
+{
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return 0;
+
+ for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
+ if (phdr == NULL)
+ break;
+ if (phdr->p_type == PT_DYNAMIC)
+ {
+ Elf_Data *data = gelf_getdata_rawchunk (elf, phdr->p_offset,
+ phdr->p_filesz, ELF_T_DYN);
+ if (data == NULL)
+ continue;
+ const size_t entsize = gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT);
+ const size_t n = data->d_size / entsize;
+ for (size_t j = 0; j < n; ++j)
+ {
+ GElf_Dyn dyn_mem;
+ GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
+ if (dyn != NULL && dyn->d_tag == DT_DEBUG)
+ return phdr->p_vaddr + bias + entsize * j + entsize / 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int
+dwfl_core_file_report (Dwfl *dwfl, Elf *core)
+{
+ if (dwfl == NULL)
+ return -1;
+
+ int result = 0;
+ const size_t ehdr_size = gelf_fsize (core, ELF_T_EHDR, 1, EV_CURRENT);
+
+ /* Record when we find a GNU build-ID note. */
+ GElf_Off build_id_offset;
+ GElf_Word build_id_size;
+ GElf_Addr build_id_vaddr;
+ inline void handle_build_id (GElf_Off offset, GElf_Word size, GElf_Addr vaddr)
+ {
+ build_id_offset = offset;
+ build_id_size = size;
+ build_id_vaddr = vaddr;
+ }
+
+ /* We've found a PT_NOTE segment inside an ELF image. Investigate. */
+ inline void handle_note (GElf_Off offset, GElf_Xword filesz, GElf_Addr vaddr)
+ {
+ Elf_Data *data = gelf_getdata_rawchunk (core, offset, filesz, ELF_T_NHDR);
+ if (data == NULL)
+ return;
+ size_t pos = 0;
+ GElf_Nhdr nhdr;
+ size_t name_offset;
+ size_t desc_offset;
+ while (pos < data->d_size
+ && (pos = gelf_getnote (data, pos,
+ &nhdr, &name_offset, &desc_offset)) > 0)
+ if (nhdr.n_type == NT_GNU_BUILD_ID
+ && nhdr.n_namesz == sizeof "GNU"
+ && !memcmp (data->d_buf + name_offset, "GNU", sizeof "GNU"))
+ handle_build_id (offset + desc_offset, nhdr.n_descsz,
+ vaddr + desc_offset);
+ }
+
+ /* We've found the PT_DYNAMIC segment inside an ELF image.
+ Return the absolute vaddr of the SONAME string if we find one. */
+ inline GElf_Addr handle_dyn (GElf_Off offset, GElf_Word filesz,
+ GElf_Addr loadbase, GElf_Addr *strtab_end,
+ GElf_Addr *r_debug)
+ {
+ GElf_Xword soname = 0;
+ GElf_Addr strtab = 0;
+ GElf_Xword strsz = 0;
+
+ Elf_Data *data = gelf_getdata_rawchunk (core, offset, filesz, ELF_T_DYN);
+ if (data == NULL)
+ return 0;
+ size_t n = data->d_size / gelf_fsize (core, ELF_T_DYN, 1, EV_CURRENT);
+ for (size_t i = 0;
+ i < n && (soname == 0 || strtab == 0 || strsz == 0);
+ ++i)
+ {
+ GElf_Dyn dyn_mem;
+ GElf_Dyn *dyn = gelf_getdyn (data, i, &dyn_mem);
+ if (dyn != NULL)
+ switch (dyn->d_tag)
+ {
+ case DT_STRTAB:
+ strtab = dyn->d_un.d_ptr;
+ continue;
+
+ case DT_STRSZ:
+ strsz = dyn->d_un.d_val;
+ continue;
+
+ case DT_SONAME:
+ soname = dyn->d_un.d_val;
+ continue;
+
+ case DT_DEBUG:
+ if (*r_debug == 0)
+ *r_debug = dyn->d_un.d_ptr;
+ continue;
+
+ default:
+ continue;
+
+ case DT_NULL:
+ break;
+ }
+ break;
+ }
+
+ if (strtab != 0)
+ {
+ *strtab_end = loadbase + strtab + strsz;
+ if (soname != 0)
+ return loadbase + strtab + soname;
+ }
+ return 0;
+ }
+
+ /* We think this PT_LOAD segment starts with an ELF header. Investigate. */
+ inline GElf_Half consider_segment (GElf_Phdr *phdr, char *header,
+ GElf_Addr *vaddr_end,
+ GElf_Off *file_size_available,
+ GElf_Off *file_size_total,
+ GElf_Addr *loadbase,
+ GElf_Addr *dyn_vaddr,
+ GElf_Word *dyn_filesz)
+ {
+ union
+ {
+ Elf32_Ehdr e32;
+ Elf64_Ehdr e64;
+ } ehdr;
+
+ Elf_Data xlatefrom =
+ {
+ .d_type = ELF_T_EHDR,
+ .d_buf = header,
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data xlateto =
+ {
+ .d_type = ELF_T_EHDR,
+ .d_buf = &ehdr,
+ .d_size = sizeof ehdr,
+ .d_version = EV_CURRENT,
+ };
+ GElf_Half e_type = ET_NONE;
+ GElf_Off phoff = 0;
+ GElf_Off shdrs_end = 0;
+ GElf_Half phnum = 0;
+ GElf_Half phentsize = 0;
+ switch (header[EI_CLASS])
+ {
+ case ELFCLASS32:
+ xlatefrom.d_size = sizeof (Elf32_Ehdr);
+ if (elf32_xlatetom (&xlateto, &xlatefrom, header[EI_DATA]) != NULL)
+ {
+ e_type = ehdr.e32.e_type;
+ phoff = ehdr.e32.e_phoff;
+ phnum = ehdr.e32.e_phnum;
+ phentsize = ehdr.e32.e_phentsize;
+ shdrs_end = ehdr.e32.e_shoff;
+ shdrs_end += ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
+ }
+ break;
+
+ case ELFCLASS64:
+ xlatefrom.d_size = sizeof (Elf64_Ehdr);
+ if (elf64_xlatetom (&xlateto, &xlatefrom, header[EI_DATA]) != NULL)
+ {
+ e_type = ehdr.e64.e_type;
+ phoff = ehdr.e64.e_phoff;
+ phnum = ehdr.e64.e_phnum;
+ phentsize = ehdr.e64.e_phentsize;
+ shdrs_end = ehdr.e64.e_shoff;
+ shdrs_end += ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
+ }
+ break;
+ }
+
+ /* We're done with the original header we read in. */
+ gelf_freechunk (core, header);
+
+ /* We see if we actually have phdrs to look at. */
+ if ((e_type != ET_EXEC && e_type != ET_DYN)
+ || phnum == 0 || phoff < ehdr_size
+ || phdr->p_filesz < phoff + phnum * phentsize
+ || phentsize != gelf_fsize (core, ELF_T_PHDR, 1, EV_CURRENT))
+ return ET_NONE;
+
+ /* Fetch the raw program headers to translate and examine. */
+ char *rawphdrs = gelf_rawchunk (core, phdr->p_offset + phoff,
+ phnum * phentsize);
+ if (rawphdrs == NULL)
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ result = -1;
+ return ET_NONE;
+ }
+ xlatefrom.d_buf = rawphdrs;
+ xlatefrom.d_size = phnum * phentsize;
+ xlatefrom.d_type = ELF_T_PHDR;
+ union
+ {
+ Elf32_Phdr p32[phnum];
+ Elf64_Phdr p64[phnum];
+ } phdrs;
+ xlateto.d_buf = &phdrs;
+ xlateto.d_size = sizeof phdrs;
+ bool phdrs_ok = false;
+ switch (ehdr.e32.e_ident[EI_CLASS])
+ {
+ case ELFCLASS32:
+ phdrs_ok = elf32_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) != NULL;
+ break;
+
+ case ELFCLASS64:
+ phdrs_ok = elf64_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e64.e_ident[EI_DATA]) != NULL;
+ break;
+ }
+ gelf_freechunk (core, rawphdrs);
+
+ if (!phdrs_ok)
+ return ET_NONE;
+
+ /* The p_align of a core file PT_LOAD segment gives the ELF page size
+ of the process that dumped the core. This is what controlled the
+ interpretation of p_offset and p_vaddr values in PT_LOAD headers
+ of objects it loaded. */
+ const GElf_Xword pagesz = phdr->p_align;
+
+ /* Consider each phdr of the embedded image. */
+ *loadbase = phdr->p_vaddr;
+ bool found_base = false;
+ GElf_Addr vaddr_limit = 0;
+ GElf_Off file_should_end = 0;
+ GElf_Off file_end = 0;
+ GElf_Off file_end_aligned = 0;
+ inline void handle_segment (GElf_Word type,
+ GElf_Addr vaddr, GElf_Off offset,
+ GElf_Xword filesz, GElf_Xword memsz)
+ {
+ switch (type)
+ {
+ case PT_LOAD:
+ /* For load segments, keep track of the bounds of the image. */
+ file_should_end = offset + filesz;
+ if (!found_base && (offset & -pagesz) == 0)
+ {
+ *loadbase = phdr->p_vaddr - (vaddr & -pagesz);
+ found_base = true;
+ }
+ vaddr_limit = (*loadbase + vaddr + memsz + pagesz - 1) & -pagesz;
+
+ /* If this segment starts contiguous with the previous one,
+ it extends the verbatim file image we have to use. */
+ if (file_end_aligned == 0
+ || (offset & -pagesz) <= file_end_aligned)
+ {
+ file_end = offset + filesz;
+ file_end_aligned = (offset + filesz + pagesz - 1) & -pagesz;
+ }
+ break;
+
+ case PT_NOTE:
+ /* For note segments, inspect the contents if they are within
+ this segment of the core file. */
+ if (offset < phdr->p_filesz && phdr->p_filesz - offset >= filesz)
+ handle_note (vaddr - phdr->p_vaddr + phdr->p_offset, filesz,
+ vaddr);
+ break;
+
+ case PT_DYNAMIC:
+ /* Save the address of the dynamic section. */
+ *dyn_vaddr = *loadbase + vaddr;
+ *dyn_filesz = filesz;
+ break;
+ }
+ }
+
+ switch (ehdr.e32.e_ident[EI_CLASS])
+ {
+ case ELFCLASS32:
+ for (uint_fast16_t i = 0; i < phnum && result >= 0; ++i)
+ handle_segment (phdrs.p32[i].p_type,
+ phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
+ phdrs.p32[i].p_filesz, phdrs.p32[i].p_memsz);
+ break;
+
+ case ELFCLASS64:
+ for (uint_fast16_t i = 0; i < phnum && result >= 0; ++i)
+ handle_segment (phdrs.p64[i].p_type,
+ phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
+ phdrs.p64[i].p_filesz, phdrs.p64[i].p_memsz);
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ /* Trim the last segment so we don't bother with zeros in the last page
+ that are off the end of the file. However, if the extra bit in that
+ page includes the section headers, keep them. */
+ if (file_end < shdrs_end && shdrs_end <= file_end_aligned)
+ file_end = shdrs_end;
+
+ /* If there were section headers in the file, we'd like to have them. */
+ if (shdrs_end != 0 && shdrs_end <= file_end
+ && shdrs_end > file_should_end)
+ file_should_end = shdrs_end;
+
+ *file_size_available = file_end;
+ *file_size_total = file_should_end;
+ *vaddr_end = vaddr_limit;
+ return e_type;
+ }
+
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
+ if (ehdr == NULL)
+ {
+ elf_error:
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+
+ size_t earlier_modules = dwfl->nmodules;
+ GElf_Addr r_debug_vaddr = 0;
+ for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (core, i, &phdr_mem);
+ if (phdr == NULL)
+ goto elf_error;
+
+ /* Consider read-only segments where we have enough to look at. */
+ if (phdr->p_type == PT_LOAD
+ && (phdr->p_flags & (PF_R|PF_W)) == PF_R
+ && phdr->p_filesz > ehdr_size)
+ {
+ /* Look at the ELF ident bytes to see if this might be an ELF file
+ image in the format of the core file. */
+ char *header = gelf_rawchunk (core, phdr->p_offset, ehdr_size);
+ if (header == NULL)
+ goto elf_error;
+ if (memcmp (header, ehdr->e_ident, EI_VERSION))
+ {
+ /* Doesn't look like the right header. */
+ gelf_freechunk (core, header);
+ continue;
+ }
+
+ /* Consider this segment. Bail if we get an unexpected error. */
+ build_id_offset = 0;
+ build_id_size = 0;
+ build_id_vaddr = 0;
+ GElf_Addr dyn_vaddr = 0;
+ GElf_Word dyn_filesz = 0;
+ GElf_Addr vaddr_end;
+ GElf_Off available_size;
+ GElf_Off whole_size;
+ GElf_Addr loadbase;
+ GElf_Half type = consider_segment (phdr, header,
+ &vaddr_end,
+ &available_size, &whole_size,
+ &loadbase,
+ &dyn_vaddr, &dyn_filesz);
+ if (result < 0)
+ break;
+
+ if (type == ET_NONE) /* Nothing there. */
+ continue;
+
+ /* Check if this segment contains the dynamic section. */
+ GElf_Addr soname_vaddr = 0;
+ GElf_Addr dynstr_end = 0;
+ inline void check_dyn (void)
+ {
+ if (soname_vaddr == 0 && dyn_vaddr != 0
+ && dyn_vaddr >= phdr->p_vaddr
+ && dyn_vaddr - phdr->p_vaddr + dyn_filesz <= phdr->p_filesz)
+ soname_vaddr = handle_dyn (dyn_vaddr - phdr->p_vaddr
+ + phdr->p_offset,
+ dyn_filesz, loadbase, &dynstr_end,
+ &r_debug_vaddr);
+ }
+
+ check_dyn ();
+
+ /* Skip some following segments if the object we found
+ has phdrs that say they are part of its segments. */
+ const uint_fast16_t considering = i;
+ GElf_Addr vaddr_start = phdr->p_vaddr & -phdr->p_align;
+ GElf_Off file_start = phdr->p_offset & -phdr->p_align;
+ GElf_Off file_end = (phdr->p_offset + phdr->p_filesz
+ + phdr->p_align - 1) & -phdr->p_align;
+ while ((phdr->p_type != PT_LOAD
+ || vaddr_end > phdr->p_vaddr + phdr->p_memsz)
+ && ++i < ehdr->e_phnum)
+ {
+ phdr = gelf_getphdr (core, i, &phdr_mem);
+ if (phdr == NULL)
+ goto elf_error;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ check_dyn ();
+
+ /* If we had all of the previous segment, we have this
+ segment as part of the contiguous file image. */
+ GElf_Off segment_start = phdr->p_offset & -phdr->p_align;
+ GElf_Off segment_end = (phdr->p_offset + phdr->p_filesz
+ + phdr->p_align - 1) & -phdr->p_align;
+ if (file_end == segment_start)
+ file_end = segment_end;
+ }
+ if (i == ehdr->e_phnum)
+ {
+ /* Somehing is amiss. Punt this supposed object we found. */
+ i = considering;
+ continue;
+ }
+
+ /* We have as much of the file as the dumped segments contain. */
+ available_size = MIN (file_end - file_start, available_size);
+
+ /* We found an object that goes from VADDR_START to VADDR_END. */
+ result = 1;
+
+ /* A dumped partial ELF file is only useful to us if it
+ contained a dynamic segment and a string table. */
+ if (available_size < whole_size
+ && (dynstr_end == 0
+ || available_size < dynstr_end - vaddr_start + file_start))
+ available_size = 0;
+
+ char *soname = NULL;
+ if (dynstr_end == 0)
+ dynstr_end = vaddr_end;
+ if (soname_vaddr >= vaddr_start && soname_vaddr < dynstr_end)
+ {
+ GElf_Off soname_offset = soname_vaddr - vaddr_start + file_start;
+ GElf_Off limit = dynstr_end - vaddr_start + file_start;
+ if (limit > file_end)
+ limit = file_end;
+ soname = string_from_offset (core, soname_offset, limit);
+ }
+
+ // XXX maybe record or verify build_id against explicit exe?
+ if (module_overlapping (dwfl, vaddr_start, vaddr_end, false) == NULL)
+ {
+ /* Record what we've learned, for find_elf to use. */
+ struct core_module_info *mod_data = malloc (sizeof *mod_data);
+ if (mod_data == NULL)
+ result = -1;
+ else
+ {
+ mod_data->offset = file_start;
+ mod_data->whole_size = available_size;
+ mod_data->l_name_vaddr = 0;
+
+ Dwfl_Module *mod = INTUSE(dwfl_report_module)
+ (dwfl,
+ soname ?: type == ET_EXEC ? "[exe]"
+ : available_size == 0 ? "[dso]" : "[dumped-dso]",
+ vaddr_start, vaddr_end);
+
+ if (mod == NULL)
+ {
+ free (mod_data);
+ result = -1;
+ }
+ else
+ {
+ /* We already eliminated duplicates. */
+ assert (mod->cb_data == NULL);
+ mod->cb_data = mod_data;
+ }
+
+ if (build_id_size != 0)
+ {
+ void *build_id = gelf_rawchunk (core, build_id_offset,
+ build_id_size);
+ if (build_id != NULL)
+ INTUSE(dwfl_module_report_build_id) (mod, build_id,
+ build_id_size,
+ build_id_vaddr);
+ gelf_freechunk (core, build_id);
+ }
+ }
+ }
+
+ if (soname != NULL)
+ gelf_freechunk (core, soname);
+
+ if (result < 0)
+ break;
+ }
+ }
+
+ if (result >= 0 && r_debug_vaddr == 0 && earlier_modules > 0)
+ /* Try to find an existing executable module with a DT_DEBUG. */
+ for (Dwfl_Module *mod = dwfl->modulelist;
+ earlier_modules-- > 0 && r_debug_vaddr == 0;
+ mod = mod->next)
+ if (mod->main.elf != NULL)
+ {
+ GElf_Addr dt_debug = find_dt_debug (mod->main.elf, mod->main.bias);
+ if (dt_debug != 0)
+ r_debug_vaddr = addr_from_memory (core, dt_debug);
+ }
+
+ if (result >= 0 && r_debug_vaddr != 0)
+ /* Now we can try to find the dynamic linker's library list. */
+ result = report_r_debug (result, core, dwfl, r_debug_vaddr);
+
+ if (result >= 0)
+ dwfl->cb_data = core;
+
+ return result;
+}
+INTDEF (dwfl_core_file_report)
+
+
+/* Dwfl_Callbacks.find_elf */
+
+int
+dwfl_core_file_find_elf (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *module_name __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ char **file_name, Elf **elfp)
+{
+ Elf *core = mod->dwfl->cb_data;
+ struct core_module_info *info = mod->cb_data;
+
+ int fd = -1;
+ *file_name = NULL;
+
+ /* If we have the whole image in the core file, just use it directly. */
+ if (info != NULL && info->whole_size != 0)
+ *elfp = gelf_begin_embedded (ELF_C_READ_MMAP_PRIVATE, core,
+ info->offset, info->whole_size);
+
+ /* If we found a build ID, try to follow that. */
+ if (*elfp == NULL && mod->build_id_len > 0)
+ {
+ fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
+ file_name, elfp);
+ if (fd >= 0)
+ return fd;
+ }
+
+ /* If we found the dynamic linker's idea of the file name, report that. */
+ if (info != NULL && info->l_name_vaddr != 0)
+ {
+ char *chunk = string_from_memory (core, info->l_name_vaddr);
+ if (chunk != NULL)
+ {
+ *file_name = strdup (chunk);
+ gelf_freechunk (core, chunk);
+ }
+ }
+
+ return fd;
+}
+INTDEF (dwfl_core_file_find_elf)
if (mod->build_id_bits != NULL)
free (mod->build_id_bits);
+
+ if (mod->build_id_bits != NULL)
+ free (mod->build_id_bits);
+
+ if (mod->cb_data != NULL)
+ free (mod->cb_data);
free (mod->name);
free (mod);
}
/* Handle describing a line record. */
typedef struct Dwfl_Line Dwfl_Line;
+/* Handle for a register map. */
+typedef struct Dwfl_Register_Map Dwfl_Register_Map;
+
/* Callbacks. */
typedef struct
{
const char *module_name, Dwarf_Addr base,
char **file_name, Elf **);
+
+/* Examine an open ET_CORE file to guess the modules used in the crashed
+ process. When the core file appears to contain whole or partial images
+ of loaded ELF files, those are identified as modules. When the core
+ image contains enough information, module names may match DSO SONAMEs. */
+extern int dwfl_core_file_report (Dwfl *dwfl, Elf *core);
+
+/* Special find_elf callback for use with dwfl_core_file_report. When the
+ core file contains a complete ELF image, this will use it directly.
+ Otherwise, it may find enough information to offer a file name. */
+extern int dwfl_core_file_find_elf (Dwfl_Module *mod, void **userdata,
+ const char *module_name, Dwarf_Addr base,
+ char **file_name, Elf **);
+
+
/* Standard argument parsing for using a standard callback set. */
struct argp;
extern const struct argp *dwfl_standard_argp (void) __attribute__ ((const));
void *arg);
+/*** Register map handling functions ***/
+
+/* Create an empty register map object. */
+extern Dwfl_Register_Map *dwfl_register_map_begin (void);
+
+/* Clean up and free a register map object. */
+extern void dwfl_register_map_end (Dwfl_Register_Map *);
+
+/* Populate the given register map with one set of registers you
+ have access to. REF supplies the machine backend that recognizes
+ the note formats. N_TYPE is the field from GElf_Nhdr for a core
+ file note that would contain this register data. OFFSET is the
+ byte offset into the note contents corresponding to the register
+ data you have, and SIZE is the number of bytes of that data.
+
+ Returns -1 for unexpected errors. Returns 0 if N_TYPE is
+ recognized but has no DWARF registers or is wholly redundant.
+ Otherwise, returns one more than the highest DWARF register number
+ now described in MAP. SETNO will be returned by dwfl_register_map
+ to refer to this register set. */
+
+extern int dwfl_register_map_populate (Dwfl_Register_Map *map, Dwfl *ref,
+ int setno,
+ GElf_Word n_type,
+ GElf_Word offset,
+ GElf_Word size);
+
+/* Look up a DWARF register number in the given register map.
+
+ Returns -1 if REGNO is not described in MAP. Otherwise, returns
+ the register set number containing REGNO and sets *OFFSET to its
+ byte position within that register set's data. */
+
+extern int dwfl_register_map (Dwfl_Register_Map *map, int regno,
+ GElf_Word *offset)
+ __nonnull_attribute__ (3);
+
+
+/* Create and populate a register map from note types found in a core file,
+ previously opened using dwfl_core_file_report. Returns the number of
+ register sets used in the map, or -1 for errors.
+
+ On success, OFFSET is filled with the location in the core file
+ of the first note providing thread register information, and
+ LIMIT is filled with the location after the last such note. */
+
+extern int dwfl_core_file_register_map (Dwfl *dwfl, Dwfl_Register_Map **result,
+ GElf_Off *offset, GElf_Off *limit)
+ __nonnull_attribute__ (2, 3, 4);
+
+/* Examine notes starting at OFFSET and not exceeding LIMIT that
+ provide register data for one thread. Returns -1 for errors.
+
+ On success, OFFSETS[] and SIZES[] are filled with the file
+ locations of the note data for the NSETS register sets described
+ by MAP. IDENT_SETNO, IDENT_POS, and IDENT_TYPE are filled to
+ describe where in register set data to find a moniker for this
+ thread. NEW_OFFSET is filled with the file position following
+ those notes. NEXT and DESC_OFFSET are filled to describe the
+ next note at *NEW_OFFSET. Returns 1 if there may be additional
+ threads in following notes. Returns 0 if following notes (if
+ any) have only non-thread data. */
+
+extern int dwfl_core_file_read_note (Dwfl *dwfl, Dwfl_Register_Map *map,
+ GElf_Off offset, GElf_Off limit,
+ int nsets,
+ GElf_Off offsets[nsets],
+ GElf_Word sizes[nsets],
+ int *ident_setno,
+ GElf_Word *ident_pos,
+ Elf_Type *ident_type,
+ // XXX non-reg info?
+ GElf_Off *new_offset,
+ GElf_Nhdr *next, GElf_Off *desc_offset)
+ __nonnull_attribute__ (6, 7, 8, 9, 10, 11, 12, 13);
+
+
+
#ifdef __cplusplus
}
#endif
{
const Dwfl_Callbacks *callbacks;
+ /* Data hook for library-supplied reporting calls and find_elf hooks. */
+ void *cb_data;
+
Dwfl_Module *modulelist; /* List in order used by full traversals. */
Dwfl_Module **modules;
Dwfl *dwfl;
struct Dwfl_Module *next; /* Link on Dwfl.modulelist. */
+ void *cb_data; /* For reporting calls' find_elf hooks. */
void *userdata;
char *name; /* Iterator name for this module. */
};
+struct Dwfl_Register_Map
+{
+ int ident_setno; /* Biased by 1. */
+ GElf_Word ident_pos;
+ Elf_Type ident_type;
+
+ int nsets;
+ GElf_Word *types;
+
+ int first;
+ int limit;
+ struct map_register *regs;
+};
+
+struct map_register
+{
+ Dwarf_Half setno:13; /* Biased by 1. */
+ Dwarf_Half offset;
+};
+
extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function;
INTDECL (dwfl_linux_kernel_report_offline)
INTDECL (dwfl_offline_section_address)
INTDECL (dwfl_module_relocate_address)
+INTDECL (dwfl_core_file_report)
+INTDECL (dwfl_core_file_find_elf)
/* Leading arguments standard to callbacks passed a Dwfl_Module. */
#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
#define PROCMAPSFMT "/proc/%d/maps"
#define PROCMEMFMT "/proc/%d/mem"
#define PROCAUXVFMT "/proc/%d/auxv"
+#define PROCEXEFMT "/proc/%d/exe"
/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag. */
if (fd < 0)
return errno == ENOENT ? 0 : errno;
- ssize_t nread;
- do
+ /* Read the whole file. */
+ char buffer[1024];
+ ssize_t nread = read (fd, buffer, sizeof buffer);
+ char *buf = buffer;
+ if (nread == sizeof buffer)
+ {
+ size_t size = sizeof buffer;
+ buf = NULL;
+ do
+ {
+ free (buf);
+ size *= 2;
+ buf = malloc (size);
+ if (buf == NULL)
+ nread = -1;
+ else
+ nread = pread64 (fd, buf, size, 0);
+ } while ((size_t) nread == size);
+ }
+ close (fd);
+
+ if (nread > 0)
{
union
{
- char buffer[sizeof (long int) * 2 * 64];
- Elf64_auxv_t a64[sizeof (long int) * 2 * 64 / sizeof (Elf64_auxv_t)];
- Elf32_auxv_t a32[sizeof (long int) * 2 * 32 / sizeof (Elf32_auxv_t)];
- } d;
- nread = read (fd, &d, sizeof d);
- if (nread > 0)
+ Elf64_Ehdr e64;
+ Elf32_Ehdr e32;
+ char ident[EI_NIDENT];
+ } u;
+ Elf *elf;
+
+ /* We need a representative ELF header to set the format of things. */
+ if (asprintf (&fname, PROCEXEFMT, pid) < 0)
+ elf = NULL;
+ else
{
- switch (sizeof (long int))
+ fd = open64 (fname, O_RDONLY);
+ free (fname);
+ if (fd < 0)
+ elf = NULL;
+ memset (&u, 0, sizeof u);
+ ssize_t hdr_read = read (fd, u.ident, sizeof u.ident);
+ close (fd);
+ if (hdr_read < (ssize_t) sizeof u.ident)
+ elf = NULL;
+ else
+ elf = elf_memory (u.ident, sizeof u);
+ }
+
+ if (elf == NULL)
+ nread = -1;
+ else
+ {
+ Elf_Data *data = gelf_getdata_memory (elf, buf, nread,
+ ELF_T_AUXV, NULL);
+ if (data == NULL)
+ nread = -1;
+ else
{
- case 4:
- for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i)
- if (d.a32[i].a_type == AT_SYSINFO_EHDR)
- {
- *sysinfo_ehdr = d.a32[i].a_un.a_val;
- nread = 0;
- break;
- }
- break;
- case 8:
- for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i)
- if (d.a64[i].a_type == AT_SYSINFO_EHDR)
- {
- *sysinfo_ehdr = d.a64[i].a_un.a_val;
- nread = 0;
- break;
- }
- break;
- default:
- abort ();
- break;
+ size_t nauxv = data->d_size / gelf_fsize (elf, ELF_T_AUXV, 1,
+ EV_CURRENT);
+ for (size_t i = 0; i < nauxv; ++i)
+ {
+ GElf_auxv_t auxv_mem;
+ GElf_auxv_t *auxv = gelf_getauxv (data, i, &auxv_mem);
+ if (auxv != NULL && auxv->a_type == AT_SYSINFO_EHDR)
+ {
+ *sysinfo_ehdr = auxv->a_un.a_val;
+ break;
+ }
+ }
+
+ //gelf_freedata (data);
}
+
+ elf_end (elf);
}
}
- while (nread > 0);
- close (fd);
+ if (buf != buffer)
+ free (buf);
return nread < 0 ? errno : 0;
}
--- /dev/null
+/* Handle register maps.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "libdwflP.h"
+
+
+Dwfl_Register_Map *
+dwfl_register_map_begin (void)
+{
+ Dwfl_Register_Map *map = calloc (1, sizeof *map);
+
+ if (map == NULL)
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+
+ return map;
+}
+
+
+void
+dwfl_register_map_end (map)
+ Dwfl_Register_Map *map;
+{
+ if (map != NULL)
+ {
+ free (map->types);
+ free (map->regs);
+ free (map);
+ }
+}
+
+static int
+expand_map (Dwfl_Register_Map *map, int first, int limit)
+{
+ if (map->regs == NULL)
+ {
+ map->regs = malloc (sizeof map->regs[0]);
+ if (unlikely (map->regs == NULL))
+ return -1;
+ map->first = first;
+ map->limit = limit;
+ }
+ else if (first < map->first)
+ {
+ struct map_register *regs
+ = realloc (map->regs, (map->limit - first) * sizeof regs[0]);
+ if (unlikely (regs == NULL))
+ return -1;
+ map->regs = memset (regs, 0, (map->first - first) * sizeof regs[0]);
+ map->first = first;
+ }
+ else if (limit > map->limit)
+ {
+ struct map_register *regs
+ = realloc (map->regs, (limit - map->first) * sizeof regs[0]);
+ if (unlikely (regs == NULL))
+ return -1;
+ memset (®s[map->limit - map->first], 0,
+ (limit - map->limit) * sizeof regs[0]);
+ map->limit = limit;
+ map->regs = regs;
+ }
+ return 0;
+}
+
+int
+dwfl_register_map_populate (map, ref, setno, type, offset, size)
+ Dwfl_Register_Map *map;
+ Dwfl *ref;
+ int setno;
+ GElf_Word type;
+ GElf_Word offset;
+ GElf_Word size;
+{
+ if (map == NULL || ref == NULL)
+ return -1;
+
+ Dwfl_Module *mod = ref->modulelist; /* XXX */
+ GElf_Addr base;
+ while (dwfl_module_getelf (mod, &base) == NULL)
+ mod = mod->next;
+ Dwfl_Error error = __libdwfl_module_getebl (mod); /* XXX */
+ Ebl *ebl = mod->ebl;
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return -1;
+ }
+
+ size_t nregloc;
+ size_t nitem;
+ const Ebl_Register_Location *reglocs;
+ const Ebl_Core_Item *items;
+ GElf_Word regs_offset;
+ int result = ebl_core_note (ebl, type, offset + size, ®s_offset,
+ &nregloc, ®locs, &nitem, &items);
+ if (result < 0)
+ {
+ __libdwfl_seterrno (DWFL_E_LIBEBL);
+ return -1;
+ }
+
+ inline void install_reg (struct map_register *reg,
+ const Ebl_Register_Location *loc, uint_fast16_t j)
+ {
+ reg->setno = setno + 1;
+ reg->offset = regs_offset + loc->offset - offset;
+ if (loc->bits % 8 == 0)
+ reg->offset += (loc->bits / 8 + loc->pad) * j;
+ else
+ abort (); /* XXX ia64 pr 1-bit */
+ }
+
+ if (result > 0)
+ {
+ result = 0;
+
+ int overlap_setno = -1;
+ size_t noverlap = 0;
+ size_t total_regs = 0;
+ for (size_t i = 0; i < nregloc; ++i)
+ {
+ const Ebl_Register_Location *loc = ®locs[i];
+
+ int first = loc->regno;
+ int limit = first + loc->count;
+ assert (first < limit);
+ result = expand_map (map, first, limit);
+ if (result < 0)
+ break;
+
+ for (uint_fast16_t j = 0; j < loc->count; ++j)
+ {
+ struct map_register *reg
+ = &map->regs[loc->regno + j - map->first];
+
+ if (reg->setno != 0 && (overlap_setno < 0
+ || overlap_setno == reg->setno))
+ {
+ ++noverlap;
+ overlap_setno = reg->setno;
+ }
+ else
+ install_reg (reg, loc, j);
+ }
+
+ total_regs += loc->count;
+ result = map->limit;
+ }
+
+ if (result > 0 && noverlap > 0)
+ {
+ /* We overlapped with an existing set.
+ See if either the old or the new set is redundant. */
+
+ if (noverlap == total_regs)
+ /* The new set is redundant. Leave it out. */
+ result = 0;
+ else
+ /* Install the new set, overriding the old. */
+ for (size_t i = 0; i < nregloc; ++i)
+ {
+ const Ebl_Register_Location *loc = ®locs[i];
+ for (uint_fast16_t j = 0; j < loc->count; ++j)
+ install_reg (&map->regs[loc->regno + j - map->first],
+ loc, j);
+ }
+ }
+
+ if (result >= 0 && map->ident_setno == 0)
+ /* Look for the moniker item. */
+ for (size_t i = 0; i < nitem; ++i)
+ if (items[i].thread_identifier && offset <= items[i].offset)
+ {
+ map->ident_setno = setno + 1;
+ map->ident_type = items[i].type;
+ map->ident_pos = items[i].offset - offset;
+ if (result == 0)
+ result = map->limit ?: 1;
+ break;
+ }
+ }
+
+ if (result > 0)
+ {
+ /* Record the set number and n_type value. */
+
+ if (map->nsets <= setno)
+ {
+ GElf_Word *types = realloc (map->types,
+ (setno + 1) * sizeof types[0]);
+ if (unlikely (types == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+ map->nsets = setno + 1;
+ map->types = memset (types, 0xff, setno * sizeof types[0]);
+ }
+
+ map->types[setno] = type;
+ }
+
+ return result;
+}
+
+int
+dwfl_register_map (map, regno, offset)
+ Dwfl_Register_Map *map;
+ int regno;
+ GElf_Word *offset;
+{
+ if (unlikely (map == NULL || regno < map->first || regno >= map->limit))
+ return -1;
+
+ const struct map_register *reg = &map->regs[regno - map->first];
+
+ *offset = reg->offset;
+ return reg->setno - 1; /* Unused slot is 0 => -1. */
+}
+2007-03-12 Roland McGrath <roland@redhat.com>
+
+ * gelf_begin_embedded.c: New file.
+ * Makefile.am (libelf_a_SOURCES): Add it.
+ * libelf.map (ELFUTILS_1.3): Add gelf_begin_embedded.
+ * gelf.h: Declare it.
+
+ * elf_begin.c (dup_elf): Renamed to ...
+ (__libelf_dup_elf): ... here, made global.
+ Take two new args with offset, size of image embedded in REF.
+ (elf_begin): Update callers.
+ * libelfP.h: Declare it.
+
+ * libelfP.h (struct Elf): Move ar.children member out of union.
+ * elf_readall.c (set_address): Work on nonarchives with children.
+ * common.h (libelf_acquire_all, libelf_release_all): Likewise.
+ * elf_end.c (elf_end): Likewise, and handle non-archive parent.
+
+2007-03-09 Roland McGrath <roland@redhat.com>
+
+ * gelf_getdata_memory.c: New file.
+ * Makefile.am (libelf_a_SOURCES): Add them.
+ * gelf.h: Declare those functions.
+ * libelf.map (ELFUTILS_1.3): Add them.
+
2007-11-03 Roland McGrath <roland@redhat.com>
* libelf.h (Elf_Data): Comment fix.
gelf_update_verdaux.c \
elf_getshnum.c elf_getshstrndx.c \
gelf_checksum.c elf32_checksum.c elf64_checksum.c \
+ gelf_getdata_memory.c gelf_getdata_rawchunk.c \
libelf_crc32.c libelf_next_prime.c \
elf_clone.c \
gelf_getlib.c gelf_update_lib.c \
elf32_offscn.c elf64_offscn.c gelf_offscn.c \
elf_getaroff.c \
- elf_gnu_hash.c
+ elf_gnu_hash.c \
+ gelf_begin_embedded.c
if !MUDFLAP
libelf_pic_a_SOURCES =
/* Common definitions for handling files in memory or only on disk.
- Copyright (C) 1998, 1999, 2000, 2002, 2005 Red Hat, Inc.
+ Copyright (C) 1998, 1999, 2000, 2002, 2005, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 1998.
{
rwlock_wrlock (elf->lock);
- if (elf->kind == ELF_K_AR)
+ Elf *child = elf->children;
+
+ while (child != NULL)
{
- Elf *child = elf->state.ar.children;
-
- while (child != NULL)
- {
- if (child->ref_count != 0)
- libelf_acquire_all (child);
- child = child->next;
- }
+ if (child->ref_count != 0)
+ libelf_acquire_all (child);
+ child = child->next;
}
}
static void
libelf_release_all (Elf *elf)
{
- if (elf->kind == ELF_K_AR)
+ Elf *child = elf->children;
+
+ while (child != NULL)
{
- Elf *child = elf->state.ar.children;
-
- while (child != NULL)
- {
- if (child->ref_count != 0)
- libelf_release_all (child);
- child = child->next;
- }
+ if (child->ref_count != 0)
+ libelf_release_all (child);
+ child = child->next;
}
rwlock_unlock (elf->lock);
/* We were asked to return a clone of an existing descriptor. This
function must be called with the lock on the parent descriptor
being held. */
-static Elf *
-dup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
+Elf *
+internal_function
+__libelf_dup_elf (int fildes, Elf_Cmd cmd, Elf *ref,
+ GElf_Off start_offset, GElf_Off maximum_size)
{
struct Elf *result;
/* Now it is time to distinguish between reading normal files and
archives. Normal files can easily be handled be incrementing the
reference counter and return the same descriptor. */
- if (ref->kind != ELF_K_AR)
+ if (ref->kind != ELF_K_AR && start_offset == 0)
{
++ref->ref_count;
return ref;
}
- /* This is an archive. We must create a descriptor for the archive
- member the internal pointer of the archive file desriptor is
- pointing to. First read the header of the next member if this
- has not happened already. */
- if (ref->state.ar.elf_ar_hdr.ar_name == NULL
- && __libelf_next_arhdr (ref) != 0)
- /* Something went wrong. Maybe there is no member left. */
- return NULL;
+ if (ref->kind == ELF_K_AR)
+ {
+ /* This is an archive. We must create a descriptor for the archive
+ member the internal pointer of the archive file desriptor is
+ pointing to. First read the header of the next member if this
+ has not happened already. */
+ if (ref->state.ar.elf_ar_hdr.ar_name == NULL
+ && __libelf_next_arhdr (ref) != 0)
+ /* Something went wrong. Maybe there is no member left. */
+ return NULL;
+
+ start_offset = ref->state.ar.offset + sizeof (struct ar_hdr);
+ maximum_size = ref->state.ar.elf_ar_hdr.ar_size;
+ }
/* We have all the information we need about the next archive member.
Now create a descriptor for it. */
- result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
- ref->state.ar.elf_ar_hdr.ar_size, cmd, ref);
+ result = read_file (fildes, start_offset, maximum_size, cmd, ref);
/* Enlist this new descriptor in the list of children. */
if (result != NULL)
{
- result->next = ref->state.ar.children;
- ref->state.ar.children = result;
+ result->next = ref->children;
+ ref->children = result;
}
return result;
case ELF_C_READ_MMAP:
if (ref != NULL)
/* Duplicate the descriptor. */
- retval = dup_elf (fildes, cmd, ref);
+ retval = __libelf_dup_elf (fildes, cmd, ref, 0, 0);
else
/* Create descriptor for existing file. */
retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
}
else
/* Duplicate this descriptor. */
- retval = dup_elf (fildes, cmd, ref);
+ retval = __libelf_dup_elf (fildes, cmd, ref, 0, 0);
}
else
/* Create descriptor for existing file. */
if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
free (elf->state.ar.ar_sym);
elf->state.ar.ar_sym = NULL;
-
- if (elf->state.ar.children != NULL)
- return 0;
}
+ if (elf->children != NULL)
+ return 0;
+
/* Remove this structure from the children list. */
parent = elf->parent;
if (parent != NULL)
rwlock_rdlock (parent->lock);
rwlock_wrlock (elf->lock);
- if (parent->state.ar.children == elf)
- parent->state.ar.children = elf->next;
+ if (parent->children == elf)
+ parent->children = elf->next;
else
{
- struct Elf *child = parent->state.ar.children;
+ struct Elf *child = parent->children;
while (child->next != elf)
child = child->next;
/* Read all of the file associated with the descriptor.
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Red Hat, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
static void
set_address (Elf *elf, size_t offset)
{
- if (elf->kind == ELF_K_AR)
- {
- Elf *child = elf->state.ar.children;
+ Elf *child = elf->children;
- while (child != NULL)
+ while (child != NULL)
+ {
+ if (child->map_address == NULL)
{
- if (child->map_address == NULL)
- {
- child->map_address = elf->map_address;
- child->start_offset -= offset;
- if (child->kind == ELF_K_AR)
- child->state.ar.offset -= offset;
+ child->map_address = elf->map_address;
+ child->start_offset -= offset;
+ if (child->kind == ELF_K_AR)
+ child->state.ar.offset -= offset;
- set_address (child, offset);
- }
-
- child = child->next;
+ set_address (child, offset);
}
+
+ child = child->next;
}
}
size_t *__name_offset, size_t *__desc_offset);
+/* Return descriptor for ELF file found embedded at OFFSET for SIZE bytes
+ in another open ELF file, to work according to CMD. */
+extern Elf *gelf_begin_embedded (Elf_Cmd __cmd, Elf *__elf,
+ GElf_Off __offset, GElf_Off __size);
+
+
+/* Get data of SIZE bytes from RAWCHUNK, translated as section data would
+ be for TYPE. If BUFFER is nonnull, it will be used for the translated
+ copy if necessary. If the result's d_buf != BUFFER, it was not used.
+ The resulting Elf_Data pointer is valid until elf_end (ELF) is called. */
+extern Elf_Data *gelf_getdata_memory (Elf *__elf,
+ const char *__rawchunk, size_t __size,
+ Elf_Type __type, void *__buffer);
+
+
/* Compute simple checksum from permanent parts of the ELF file. */
extern long int gelf_checksum (Elf *__elf);
--- /dev/null
+/* Create Elf descriptor from image embedded in an ELF file.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+
+#include "libelfP.h"
+
+
+Elf *
+gelf_begin_embedded (cmd, ref, offset, size)
+ Elf_Cmd cmd;
+ Elf *ref;
+ GElf_Off offset;
+ GElf_Off size;
+{
+ if (ref == NULL)
+ return NULL;
+
+ if (offset == 0 || size == 0
+ || offset >= ref->maximum_size || ref->maximum_size - offset < size)
+ {
+ __libelf_seterrno (ELF_E_INVALID_OPERAND);
+ return NULL;
+ }
+
+ return __libelf_dup_elf (-1, cmd, ref, offset, size);
+}
--- /dev/null
+/* Return converted data from raw chunk supplied in memory.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libelfP.h"
+#include <system.h>
+#include "common.h"
+#include "elf-knowledge.h"
+
+Elf_Data *
+gelf_getdata_memory (elf, rawchunk, size, type, buffer)
+ Elf *elf;
+ const char *rawchunk;
+ size_t size;
+ Elf_Type type;
+ void *buffer;
+{
+ if (elf == NULL || elf->kind != ELF_K_ELF)
+ return NULL;
+
+ if (type >= ELF_T_NUM)
+ {
+ __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
+ return NULL;
+ }
+
+ size_t align = __libelf_type_align (elf->class, type);
+
+ int flags = 0;
+ inline bool check_buffer (void)
+ {
+ if (buffer == NULL)
+ {
+ buffer = malloc (size);
+ if (buffer == NULL)
+ return true;
+ flags = ELF_F_MALLOCED;
+ }
+ return false;
+ }
+
+ if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
+ {
+ if (((uintptr_t) rawchunk & (align - 1)) == 0)
+ /* No need to copy, we can use the raw data. */
+ buffer = (void *) rawchunk;
+ else
+ {
+ if (check_buffer ())
+ goto nomem;
+
+ /* The copy will be appropriately aligned for direct access. */
+ memcpy (buffer, rawchunk, size);
+ }
+ }
+ else
+ {
+ if (check_buffer ())
+ goto nomem;
+
+ /* Call the conversion function. */
+ (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type])
+ (buffer, rawchunk, size, 0);
+ }
+
+ Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
+ if (chunk == NULL)
+ {
+ nomem:
+ __libelf_seterrno (ELF_E_NOMEM);
+ return NULL;
+ }
+
+ chunk->dummy_scn.elf = elf;
+ chunk->dummy_scn.flags = flags;
+ chunk->data.s = &chunk->dummy_scn;
+ chunk->data.d.d_buf = buffer;
+ chunk->data.d.d_size = size;
+ chunk->data.d.d_type = type;
+ chunk->data.d.d_align = align;
+ chunk->data.d.d_version = __libelf_version;
+
+ chunk->next = elf->state.elf.rawchunks;
+ elf->state.elf.rawchunks = chunk;
+
+ return &chunk->data.d;
+}
+INTDEF (gelf_getdata_memory)
--- /dev/null
+/* Return converted data from raw chunk of ELF file.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "libelfP.h"
+
+Elf_Data *
+gelf_getdata_rawchunk (elf, offset, size, type)
+ Elf *elf;
+ GElf_Off offset;
+ GElf_Word size;
+ Elf_Type type;
+{
+ /* Get the raw bytes from the file. */
+ char *rawchunk = INTUSE(gelf_rawchunk) (elf, offset, size);
+ if (rawchunk == NULL)
+ return NULL;
+
+ /* We'll reuse the buffer if we didn't map the file directly. */
+ bool alloced = (rawchunk < (char *) elf->map_address + elf->start_offset
+ || rawchunk >= ((char *) elf->map_address + elf->start_offset
+ + elf->maximum_size));
+
+ Elf_Data *data = INTUSE(gelf_getdata_memory) (elf, rawchunk, size, type,
+ alloced ? rawchunk : NULL);
+
+ if (data != NULL)
+ {
+ Elf_Data_Chunk *chunk = (Elf_Data_Chunk *) data;
+ if (alloced)
+ {
+ /* It should have been converted in place.
+ elf_end will free our original RAWCHUNK pointer. */
+ assert (chunk->dummy_scn.flags == 0);
+ chunk->dummy_scn.flags = ELF_F_MALLOCED;
+ }
+ }
+ else if (alloced)
+ free (rawchunk);
+
+ return data;
+}
gelf_getauxv;
gelf_update_auxv;
gelf_getnote;
+ gelf_getdata_memory;
+ gelf_getdata_rawchunk;
+ gelf_begin_embedded;
};
int ref_count;
struct Elf *next; /* Used in list of archive descriptors. */
+ struct Elf *children; /* List of all descriptors pointing to this one. */
union
{
char ar_name[16]; /* NUL terminated ar_name of elf_ar_hdr. */
char raw_name[17]; /* This is a buffer for the NUL terminated
named raw_name used in the elf_ar_hdr. */
- struct Elf *children; /* List of all descriptors for this archive. */
} ar;
} state;
unsigned int __version);
+/* Create Elf descriptor from image embedded in reference file. */
+extern Elf *__libelf_dup_elf (int fildes, Elf_Cmd cmd, Elf *ref,
+ GElf_Off start_offset, GElf_Off maximum_size)
+ internal_function;
+
/* Create Elf descriptor from memory image. */
extern Elf *__libelf_read_mmaped_file (int fildes, void *map_address,
off_t offset, size_t maxsize,
extern uint32_t __libelf_crc32 (uint32_t crc, unsigned char *buf, size_t len)
attribute_hidden;
+INTDECL (gelf_rawchunk);
+INTDECL (gelf_freechunk);
+INTDECL (gelf_getdata_memory);
+
/* We often have to update a flag iff a value changed. Make this
convenient. */
+2007-08-04 Roland McGrath <roland@redhat.com>
+
+ * dwflmodtest.c (print_module_build_id): New function.
+ (list_module, print_module): Call it.
+
+2007-05-03 Roland McGrath <roland@redhat.com>
+
+ * coreregs.c (handle_core_file): Close FD.
+
+2007-04-08 Roland McGrath <roland@redhat.com>
+
+ * coreregs.c: New file.
+ * Makefile.am (noinst_PROGRAMS): Add it.
+ (coreregs_LDADD): New variable.
+
2007-10-20 Roland McGrath <roland@redhat.com>
* run-dwfl-addr-sect.sh: Change expected output, no errors.
show-abbrev hash newscn ecp dwflmodtest \
find-prologues funcretval allregs rdwrmmap \
dwfl-bug-addr-overflow arls dwfl-bug-fd-leak \
- dwfl-addr-sect dwfl-bug-report
+ dwfl-addr-sect dwfl-bug-report coreregs
# get-ciefde
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
asm-tst6 asm-tst7 asm-tst8 asm-tst9
dwfl_bug_fd_leak_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
dwfl_bug_report_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
dwfl_addr_sect_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
+coreregs_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
CLEANFILES = xxx *.gcno *.gcda *gconv
--- /dev/null
+/* Test program for libdwfl core file handling.
+ Copyright (C) 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <error.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <dwarf.h>
+#include ELFUTILS_HEADER(dwfl)
+#include "../libdwfl/libdwflP.h" /* XXX */
+
+
+typedef uint8_t GElf_Byte;
+
+static void
+convert (Elf *core, Elf_Type type, void *value, void *data)
+{
+ Elf_Data valuedata =
+ {
+ .d_type = type,
+ .d_buf = value,
+ .d_size = gelf_fsize (core, type, 1, EV_CURRENT),
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data indata =
+ {
+ .d_type = type,
+ .d_buf = data,
+ .d_size = valuedata.d_size,
+ .d_version = EV_CURRENT,
+ };
+
+ Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
+ ? elf32_xlatetom : elf64_xlatetom)
+ (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
+ if (d == NULL)
+ error (2, 0, "elf_xlatetom: %s", elf_errmsg (-1));
+}
+
+static void
+handle_thread_identifier (Elf *core, Elf_Type type, void *data)
+{
+#define TYPES \
+ DO_TYPE (BYTE, Byte, "0x%.2" PRIx8); DO_TYPE (HALF, Half, "0x%.4" PRIx16); \
+ DO_TYPE (WORD, Word, "0x%.8" PRIx32); DO_TYPE (SWORD, Sword, "%" PRId32); \
+ DO_TYPE (XWORD, Xword, "0x%.16" PRIx64); DO_TYPE (SXWORD, Sxword, "%" PRId64)
+
+#define DO_TYPE(NAME, Name, fmt) GElf_##Name Name
+ union { TYPES; } value;
+#undef DO_TYPE
+
+ convert (core, type, &value, data);
+
+ printf (" thread identifier: ");
+ switch (type)
+ {
+ default:
+ abort ();
+ break;
+
+#define DO_TYPE(NAME, Name, fmt) \
+ case ELF_T_##NAME: \
+ printf (fmt, value.Name); \
+ break
+ TYPES;
+#undef DO_TYPE
+ }
+ putchar_unlocked ('\n');
+
+#undef TYPES
+}
+
+static void
+handle_register_data (Dwfl *dwfl, Elf *core,
+ int regno, const char *regname, int bits, int type,
+ void *data)
+{
+#define TYPES \
+ BITS (8, BYTE, "%" PRId8, "0x%.2" PRIx8); \
+ BITS (16, HALF, "%" PRId16, "0x%.4" PRIx16); \
+ BITS (32, WORD, "%" PRId32, "0x%.8" PRIx32); \
+ BITS (64, XWORD, "%" PRId64, "0x%.16" PRIx64)
+
+#define BITS(bits, xtype, sfmt, ufmt) uint##bits##_t b##bits
+ union { TYPES; } value;
+#undef BITS
+
+ printf ("%9s (%2d): ", regname, regno);
+
+ Dwarf_Addr addr = 0;
+ switch (type)
+ {
+ case DW_ATE_unsigned:
+ case DW_ATE_signed:
+ case DW_ATE_address:
+ switch (bits)
+ {
+#define BITS(bits, xtype, sfmt, ufmt) \
+ case bits: \
+ convert (core, ELF_T_##xtype, &value, data); \
+ if (type == DW_ATE_signed) \
+ printf (sfmt, value.b##bits); \
+ else \
+ printf (ufmt, value.b##bits); \
+ addr = value.b##bits; \
+ break
+
+ TYPES;
+
+ default:
+ abort ();
+#undef BITS
+ }
+ break;
+
+ default:
+ assert (bits % 8 == 0);
+ break;
+ }
+
+ if (type == DW_ATE_address)
+ {
+ GElf_Sym sym;
+ const char *name = dwfl_module_addrsym (dwfl_addrmodule (dwfl, addr),
+ addr, &sym, NULL);
+ if (name != NULL)
+ {
+ if (addr == sym.st_value)
+ printf ("\t<%s>", name);
+ else
+ printf ("\t<%s%+" PRId64 ">", name, addr - sym.st_value);
+ }
+ }
+
+ putchar_unlocked ('\n');
+
+#undef TYPES
+}
+
+static void
+handle_thread (Dwfl *dwfl, Elf *core, Dwfl_Register_Map *map,
+ int nsets, GElf_Off offsets[], GElf_Word sizes[],
+ int idset, GElf_Word idpos, Elf_Type idtype)
+{
+ void *sets[nsets];
+ memset (sets, 0, sizeof sets);
+ inline int establish (int setno)
+ {
+ if (sets[setno] == NULL)
+ {
+ if (sizes[setno] == 0)
+ return 1;
+ sets[setno] = gelf_rawchunk (core, offsets[setno], sizes[setno]);
+ if (sets[setno] == NULL)
+ return -1;
+ }
+ return 0;
+ }
+ int handle_register (void *arg __attribute__ ((unused)),
+ int regno,
+ const char *setname __attribute__ ((unused)),
+ const char *prefix __attribute__ ((unused)),
+ const char *regname,
+ int bits, int type)
+ {
+ GElf_Word offset;
+ int setno = dwfl_register_map (map, regno, &offset);
+ if (setno >= 0)
+ {
+ int result = establish (setno);
+ if (result == 0)
+ handle_register_data (dwfl, core, regno, regname, bits, type,
+ sets[setno] + offset);
+ else if (result < 0)
+ error (2, 0, "gelf_rawchunk: %s", elf_errmsg (-1));
+ }
+ return 0;
+ }
+
+ if (idset < 0)
+ puts (" no thread identifier!");
+ else
+ {
+ int result = establish (idset);
+ if (result < 0)
+ error (2, 0, "gelf_rawchunk: %s", elf_errmsg (-1));
+ assert (result == 0);
+
+ handle_thread_identifier (core, idtype, sets[idset] + idpos);
+ }
+
+ Dwfl_Module *mod = dwfl->modulelist; /* XXX */
+ GElf_Addr base;
+ while (dwfl_module_getelf (mod, &base) == NULL)
+ mod = mod->next;
+ int result = dwfl_module_register_names (mod, &handle_register, NULL);
+ assert (result == 0);
+
+ for (int i = 0; i < nsets; ++i)
+ if (sets[i] != NULL)
+ gelf_freechunk (core, sets[i]);
+}
+
+static void
+find_registers (Dwfl *dwfl, Elf *core)
+{
+ GElf_Off offset;
+ GElf_Off limit;
+ Dwfl_Register_Map *map;
+ int nsets = dwfl_core_file_register_map (dwfl, &map, &offset, &limit);
+ if (nsets < 0)
+ error (2, 0, "dwfl_core_file_register_map: %s", dwfl_errmsg (-1));
+
+ if (nsets == 0)
+ {
+ puts (" no register information");
+ return;
+ }
+
+ GElf_Off offsets[nsets];
+ GElf_Word sizes[nsets];
+ int result;
+ do
+ {
+ int idset;
+ GElf_Word idpos;
+ Elf_Type idtype;
+ GElf_Nhdr nhdr;
+ GElf_Off note_offset;
+ result = dwfl_core_file_read_note (dwfl, map, offset, limit, nsets,
+ offsets, sizes,
+ &idset, &idpos, &idtype,
+ &offset, &nhdr, ¬e_offset);
+ if (result >= 0)
+ handle_thread (dwfl, core, map, nsets,
+ offsets, sizes, idset, idpos, idtype);
+ if (result == 0)
+ {
+ /* Non-thread note. */
+ offset = note_offset + nhdr.n_descsz;
+ break;
+ }
+ } while (result >= 0 && offset < limit);
+
+ if (result < 0)
+ error (2, 0, "dwfl_core_file_read_note: %s", dwfl_errmsg (-1));
+
+ dwfl_register_map_end (map);
+}
+
+static const Dwfl_Callbacks corefile_callbacks =
+ {
+ .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+ .find_elf = INTUSE(dwfl_core_file_find_elf),
+ };
+
+static void
+handle_core_file (const char *name)
+{
+ int fd = open64 (name, O_RDONLY);
+ if (fd < 0)
+ error (2, errno, "cannot open '%s'", name);
+
+ elf_version (EV_CURRENT);
+ Elf *core = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+ if (core == NULL)
+ error (2, 0, "cannot read ELF core file: %s", elf_errmsg (-1));
+
+ Dwfl *dwfl = dwfl_begin (&corefile_callbacks);
+ int result = dwfl_core_file_report (dwfl, core);
+ if (result < 0)
+ error (2, 0, "%s: %s", name, dwfl_errmsg (-1));
+ dwfl_report_end (dwfl, NULL, NULL);
+
+ printf ("%s:\n", name);
+ find_registers (dwfl, core);
+
+ dwfl_end (dwfl);
+ elf_end (core);
+ close (fd);
+}
+
+int
+main (int argc, char **argv)
+{
+ /* We use no threads here which can interfere with handling a stream. */
+ (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+
+ /* Set locale. */
+ (void) setlocale (LC_ALL, "");
+
+ for (int i = 1; i < argc; ++i)
+ handle_core_file (argv[i]);
+
+ return 0;
+}
return DWARF_CB_OK;
}
+static void
+print_module_build_id (Dwfl_Module *mod, const char *name)
+{
+ const unsigned char *bits;
+ GElf_Addr vaddr;
+ int len = dwfl_module_build_id (mod, &bits, &vaddr);
+ if (len < 0)
+ error (0, 0, "dwfl_module_build_id: %s: %s", name, dwfl_errmsg (-1));
+ if (len > 0)
+ {
+ fputs ("\tID: ", stdout);
+ while (len-- > 0)
+ printf ("%02" PRIx8, *bits++);
+ if (vaddr == 0)
+ putchar ('\n');
+ else
+ printf (" @ %#" PRIx64 "\n", vaddr);
+ }
+}
+
static int
-list_module (Dwfl_Module *mod __attribute__ ((unused)),
+list_module (Dwfl_Module *mod,
void **userdata __attribute__ ((unused)),
const char *name, Dwarf_Addr base,
void *arg __attribute__ ((unused)))
abort ();
printf ("module: %30s %08" PRIx64 "..%08" PRIx64 " %s %s\n",
name, start, end, file, debug);
+ print_module_build_id (mod, name);
return DWARF_CB_OK;
}
static int
-print_module (Dwfl_Module *mod __attribute__ ((unused)),
+print_module (Dwfl_Module *mod,
void **userdata __attribute__ ((unused)),
const char *name, Dwarf_Addr base,
Dwarf *dw, Dwarf_Addr bias,
{
printf ("module: %30s %08" PRIx64 " %s %" PRIx64 " (%s)\n",
name, base, dw == NULL ? "no" : "DWARF", bias, dwfl_errmsg (-1));
+ print_module_build_id (mod, name);
if (dw != NULL && *(const bool *) arg)
{