[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Libunwind-devel] [PATCHv2 3/3] Add core dump unwinding support to libun
From: |
Denys Vlasenko |
Subject: |
[Libunwind-devel] [PATCHv2 3/3] Add core dump unwinding support to libunwind |
Date: |
Tue, 21 Feb 2012 18:22:47 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20120131 Thunderbird/10.0 |
On 02/21/2012 06:19 PM, Denys Vlasenko wrote:
Patch 3:
Add src/coredump/*. Took the review comments into an account:
uses code commonalized in patches 1, 2; reformatted to follow the style.
--
vda
diff -d -urpN libunwind.2/configure.in libunwind.3/configure.in
--- libunwind.2/configure.in 2012-02-13 18:43:50.000000000 +0100
+++ libunwind.3/configure.in 2012-02-21 17:58:31.210417230 +0100
@@ -44,6 +44,7 @@ AC_C_CONST
AC_C_INLINE
AC_TYPE_SIGNAL
AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(off_t)
CPPFLAGS="${CPPFLAGS} -D_GNU_SOURCE"
diff -d -urpN libunwind.2/include/libunwind-coredump.h
libunwind.3/include/libunwind-coredump.h
--- libunwind.2/include/libunwind-coredump.h 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/include/libunwind-coredump.h 2012-02-21 17:58:31.210417230
+0100
@@ -0,0 +1,66 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef libunwind_coredump_h
+#define libunwind_coredump_h
+
+#include <libunwind.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Helper routines which make it easy to use libunwind on a coredump.
+ They're available only if UNW_REMOTE_ONLY is _not_ defined and they
+ aren't really part of the libunwind API. They are implemented in a
+ archive library called libunwind-coredump.a. */
+
+struct UCD_info;
+
+extern struct UCD_info *_UCD_create(const char *filename);
+extern void _UCD_destroy(struct UCD_info *);
+
+extern int _UCD_add_backing_file(struct UCD_info *, int phdr_no, const char
*filename);
+
+extern int _UCD_find_proc_info (unw_addr_space_t, unw_word_t,
+ unw_proc_info_t *, int, void *);
+extern void _UCD_put_unwind_info (unw_addr_space_t, unw_proc_info_t *, void *);
+extern int _UCD_get_dyn_info_list_addr (unw_addr_space_t, unw_word_t *,
+ void *);
+extern int _UCD_access_mem (unw_addr_space_t, unw_word_t, unw_word_t *, int,
+ void *);
+extern int _UCD_access_reg (unw_addr_space_t, unw_regnum_t, unw_word_t *,
+ int, void *);
+extern int _UCD_access_fpreg (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *,
+ int, void *);
+extern int _UCD_get_proc_name (unw_addr_space_t, unw_word_t, char *, size_t,
+ unw_word_t *, void *);
+extern int _UCD_resume (unw_addr_space_t, unw_cursor_t *, void *);
+extern unw_accessors_t _UCD_accessors;
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* libunwind_coredump_h */
diff -d -urpN libunwind.2/Makefile.am libunwind.3/Makefile.am
--- libunwind.2/Makefile.am 2012-02-13 18:43:50.000000000 +0100
+++ libunwind.3/Makefile.am 2012-02-21 17:58:31.210417230 +0100
@@ -1,4 +1,6 @@
-include_HEADERS = include/libunwind-dynamic.h include/libunwind-ptrace.h
+include_HEADERS = include/libunwind-dynamic.h \
+ include/libunwind-ptrace.h \
+ include/libunwind-coredump.h
if ARCH_ARM
include_HEADERS += include/libunwind-arm.h
diff -d -urpN libunwind.2/src/coredump/example-core-unwind.c
libunwind.3/src/coredump/example-core-unwind.c
--- libunwind.2/src/coredump/example-core-unwind.c 1970-01-01
01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/example-core-unwind.c 2012-02-21
18:03:23.400383339 +0100
@@ -0,0 +1,310 @@
+/*
+ * Example program for unwinding core dumps.
+ *
+ * Compile a-la:
+ * gcc -Os -Wall \
+ * -Wl,--start-group \
+ * -lunwind -lunwind-x86 -lunwind-coredump \
+ * example-core-unwind.c \
+ * -Wl,--end-group \
+ * -oexample-core-unwind
+ *
+ * Run:
+ * objdump -sx COREDUMP
+ * eu-unstrip -n --core COREDUMP
+ * figure out which segments in COREDUMP correspond to which mapped
executable files
+ * (binary and libraries), then supply them like this:
+ * ./example-core-unwind COREDUMP 3:/bin/crashed_program 6:/lib/libc.so.6 [...]
+ */
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#undef __USE_GNU
+#define __USE_GNU 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdbool.h>
+/* Try to pull in PATH_MAX */
+#include <limits.h>
+#include <sys/param.h>
+#ifndef PATH_MAX
+# define PATH_MAX 256
+#endif
+#include <pwd.h>
+#include <grp.h>
+#include <syslog.h>
+
+/* For SIGSEGV handler code */
+#include <execinfo.h>
+#include <sys/ucontext.h>
+
+#include <libunwind-coredump.h>
+
+
+/* Utility logging functions */
+
+enum {
+ LOGMODE_NONE = 0,
+ LOGMODE_STDIO = (1 << 0),
+ LOGMODE_SYSLOG = (1 << 1),
+ LOGMODE_BOTH = LOGMODE_SYSLOG + LOGMODE_STDIO,
+};
+const char *msg_prefix = "";
+const char *msg_eol = "\n";
+int logmode = LOGMODE_STDIO;
+int xfunc_error_retval = EXIT_FAILURE;
+
+void xfunc_die(void)
+{
+ exit(xfunc_error_retval);
+}
+
+static void verror_msg_helper(const char *s,
+ va_list p,
+ const char* strerr,
+ int flags)
+{
+ char *msg;
+ int prefix_len, strerr_len, msgeol_len, used;
+
+ if (!logmode)
+ return;
+
+ used = vasprintf(&msg, s, p);
+ if (used < 0)
+ return;
+
+ /* This is ugly and costs +60 bytes compared to multiple
+ * fprintf's, but is guaranteed to do a single write.
+ * This is needed for e.g. when multiple children
+ * can produce log messages simultaneously. */
+
+ prefix_len = msg_prefix[0] ? strlen(msg_prefix) + 2 : 0;
+ strerr_len = strerr ? strlen(strerr) : 0;
+ msgeol_len = strlen(msg_eol);
+ /* +3 is for ": " before strerr and for terminating NUL */
+ char *msg1 = (char*) realloc(msg, prefix_len + used + strerr_len +
msgeol_len + 3);
+ if (!msg1) {
+ free(msg);
+ return;
+ }
+ msg = msg1;
+ /* TODO: maybe use writev instead of memmoving? Need full_writev? */
+ if (prefix_len) {
+ char *p;
+ memmove(msg + prefix_len, msg, used);
+ used += prefix_len;
+ p = stpcpy(msg, msg_prefix);
+ p[0] = ':';
+ p[1] = ' ';
+ }
+ if (strerr) {
+ if (s[0]) {
+ msg[used++] = ':';
+ msg[used++] = ' ';
+ }
+ strcpy(&msg[used], strerr);
+ used += strerr_len;
+ }
+ strcpy(&msg[used], msg_eol);
+
+ if (flags & LOGMODE_STDIO) {
+ fflush(stdout);
+ write(STDERR_FILENO, msg, used + msgeol_len);
+ }
+ msg[used] = '\0'; /* remove msg_eol (usually "\n") */
+ if (flags & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msg + prefix_len);
+ }
+ free(msg);
+}
+
+void log_msg(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ verror_msg_helper(s, p, NULL, logmode);
+ va_end(p);
+}
+/* It's a macro, not function, since it collides with log() from math.h */
+#undef log
+#define log(...) log_msg(__VA_ARGS__)
+
+void error_msg(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ verror_msg_helper(s, p, NULL, logmode);
+ va_end(p);
+}
+
+void error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ verror_msg_helper(s, p, NULL, logmode);
+ va_end(p);
+ xfunc_die();
+}
+
+void perror_msg(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ /* Guard against "<error message>: Success" */
+ verror_msg_helper(s, p, errno ? strerror(errno) : NULL, logmode);
+ va_end(p);
+}
+
+void perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+ va_start(p, s);
+ /* Guard against "<error message>: Success" */
+ verror_msg_helper(s, p, errno ? strerror(errno) : NULL, logmode);
+ va_end(p);
+ xfunc_die();
+}
+
+void die_out_of_memory(void)
+{
+ error_msg_and_die("Out of memory, exiting");
+}
+
+/* End of utility logging functions */
+
+
+
+static
+void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
+{
+ long ip;
+ ucontext_t *uc;
+
+ uc = ucontext;
+ ip = uc->uc_mcontext.gregs[REG_EIP];
+ dprintf(2, "signal:%d address:0x%lx ip:0x%lx\n",
+ sig,
+ /* this is void*, but using %p would print "(null)"
+ * even for ptrs which are not exactly 0, but, say,
0x123:
+ */
+ (long)info->si_addr,
+ ip);
+ {
+ /* glibc extension */
+ void *array[50];
+ int size;
+ size = backtrace(array, 50);
+ backtrace_symbols_fd(array, size, 2);
+ }
+ _exit(1);
+}
+
+static void install_sigsegv_handler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = handle_sigsegv;
+ sa.sa_flags = SA_SIGINFO;
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGILL, &sa, NULL);
+ sigaction(SIGFPE, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+int
+main(int argc, char **argv)
+{
+ unw_addr_space_t as;
+ struct UCD_info *ui;
+ unw_cursor_t c;
+ int ret;
+
+ install_sigsegv_handler();
+
+ const char *progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ if (!argv[1])
+ error_msg_and_die("Usage: %s COREDUMP
[SEGMENT_NO:BINARY_FILE]...", progname);
+
+ msg_prefix = progname;
+
+ as = unw_create_addr_space(&_UCD_accessors, 0);
+ if (!as)
+ error_msg_and_die("unw_create_addr_space() failed");
+
+ ui = _UCD_create(argv[1]);
+ if (!ui)
+ error_msg_and_die("_UCD_create('%s') failed", argv[1]);
+ ret = unw_init_remote(&c, as, ui);
+ if (ret < 0)
+ error_msg_and_die("unw_init_remote() failed: ret=%d\n", ret);
+
+ argv += 2;
+ while (*argv) {
+ char *colon = strchr(*argv, ':');
+ if (!colon)
+ error_msg_and_die("Bad format: '%s'", *argv);
+ *colon = '\0';
+ unsigned n = atoi(*argv);
+ *colon = ':';
+ if (_UCD_add_backing_file(ui, n, colon + 1) < 0)
+ error_msg_and_die("Can't add backing file '%s'", *argv);
+ argv++;
+ }
+
+ for (;;) {
+ unw_word_t ip;
+ ret = unw_get_reg(&c, UNW_REG_IP, &ip);
+ if (ret < 0)
+ error_msg_and_die("unw_get_reg(UNW_REG_IP) failed:
ret=%d\n", ret);
+
+ unw_proc_info_t pi;
+ ret = unw_get_proc_info(&c, &pi);
+ if (ret < 0)
+ error_msg_and_die("unw_get_proc_info(ip=0x%lx) failed:
ret=%d\n", (long) ip, ret);
+ printf("\tip=0x%08lx proc=%08lx-%08lx handler=0x%08lx
lsda=0x%08lx\n",
+ (long) ip,
+ (long) pi.start_ip, (long) pi.end_ip,
+ (long) pi.handler, (long) pi.lsda);
+
+ log("step");
+ ret = unw_step(&c);
+ log("step done:%d", ret);
+ if (ret < 0)
+ error_msg_and_die("FAILURE: unw_step() returned %d",
ret);
+ if (ret == 0)
+ break;
+ }
+ log("stepping ended");
+
+ _UCD_destroy(ui);
+
+ return 0;
+}
diff -d -urpN libunwind.2/src/coredump/README libunwind.3/src/coredump/README
--- libunwind.2/src/coredump/README 1970-01-01 01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/README 2012-02-21 17:58:31.211417235 +0100
@@ -0,0 +1,8 @@
+This code is based on "unwinding via ptrace" code from ptrace/
+directory.
+
+Files with names starting with _UCD_ are substantially changed
+from their ptrace/_UPT_... progenitors.
+
+Files which still have _UPT_... names are either verbiatim copies
+from ptrace/, or unimplemented stubs.
diff -d -urpN libunwind.2/src/coredump/_UCD_access_mem.c
libunwind.3/src/coredump/_UCD_access_mem.c
--- libunwind.2/src/coredump/_UCD_access_mem.c 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UCD_access_mem.c 2012-02-21 18:03:23.400383339
+0100
@@ -0,0 +1,102 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+int
+_UCD_access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
+ int write, void *arg)
+{
+ if (write)
+ {
+ Debug(0, "%s: write is not supported\n", __func__);
+ return -UNW_EINVAL;
+ }
+
+ struct UCD_info *ui = arg;
+
+ unw_word_t addr_last = addr + sizeof(*val)-1;
+ coredump_phdr_t *phdr;
+ unsigned i;
+ for (i = 0; i < ui->phdrs_count; i++)
+ {
+ phdr = &ui->phdrs[i];
+ if (phdr->p_vaddr <= addr && addr_last < phdr->p_vaddr + phdr->p_memsz)
+ {
+ goto found;
+ }
+ }
+ Debug(1, "%s: addr 0x%llx is unmapped\n",
+ __func__, (unsigned long long)addr
+ );
+ return -UNW_EINVAL;
+
+ found: ;
+
+ const char *filename;
+ off_t fileofs;
+ int fd;
+ if (addr_last >= phdr->p_vaddr + phdr->p_filesz)
+ {
+ /* This part of mapped address space is not present in coredump file */
+ /* Do we have it in the backup file? */
+ if (phdr->backing_fd < 0)
+ {
+ Debug(1, "%s: access to not-present data in phdr[%d]: addr:0x%llx\n",
+ __func__, i, (unsigned long long)addr
+ );
+ return -UNW_EINVAL;
+ }
+ filename = phdr->backing_filename;
+ fileofs = addr - phdr->p_vaddr;
+ fd = phdr->backing_fd;
+ goto read;
+ }
+
+ filename = ui->coredump_filename;
+ fileofs = phdr->p_offset + (addr - phdr->p_vaddr);
+ fd = ui->coredump_fd;
+ read:
+ if (lseek(fd, fileofs, SEEK_SET) != fileofs)
+ goto read_error;
+ if (read(fd, val, sizeof(*val)) != sizeof(*val))
+ goto read_error;
+
+ Debug(1, "%s: 0x%llx <- [addr:0x%llx fileofs:0x%llx]\n",
+ __func__,
+ (unsigned long long)(*val),
+ (unsigned long long)addr,
+ (unsigned long long)fileofs
+ );
+ return 0;
+
+ read_error:
+ Debug(1, "%s: access out of file: addr:0x%llx fileofs:%llx file:'%s'\n",
+ __func__,
+ (unsigned long long)addr,
+ (unsigned long long)fileofs,
+ filename
+ );
+ return -UNW_EINVAL;
+}
diff -d -urpN libunwind.2/src/coredump/_UCD_accessors.c
libunwind.3/src/coredump/_UCD_accessors.c
--- libunwind.2/src/coredump/_UCD_accessors.c 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UCD_accessors.c 2012-02-21 18:03:23.400383339
+0100
@@ -0,0 +1,36 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_internal.h"
+
+PROTECTED unw_accessors_t _UCD_accessors =
+ {
+ .find_proc_info = _UCD_find_proc_info,
+ .put_unwind_info = _UCD_put_unwind_info,
+ .get_dyn_info_list_addr = _UCD_get_dyn_info_list_addr,
+ .access_mem = _UCD_access_mem,
+ .access_reg = _UCD_access_reg,
+ .access_fpreg = _UCD_access_fpreg,
+ .resume = _UCD_resume,
+ .get_proc_name = _UCD_get_proc_name
+ };
diff -d -urpN libunwind.2/src/coredump/_UCD_access_reg.c
libunwind.3/src/coredump/_UCD_access_reg.c
--- libunwind.2/src/coredump/_UCD_access_reg.c 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UCD_access_reg.c 2012-02-21 18:03:23.400383339
+0100
@@ -0,0 +1,92 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+
+#include "_UCD_internal.h"
+
+int
+_UCD_access_reg (unw_addr_space_t as,
+ unw_regnum_t regnum, unw_word_t *valp,
+ int write, void *arg)
+{
+ if (write)
+ {
+ Debug(0, "%s: write is not supported\n", __func__);
+ return -UNW_EINVAL;
+ }
+
+#if defined(UNW_TARGET_X86)
+ static const uint8_t remap_regs[] =
+ {
+ /* names from libunwind-x86.h */
+ [UNW_X86_EAX] = offsetof(struct user_regs_struct, eax) / sizeof(long),
+ [UNW_X86_EDX] = offsetof(struct user_regs_struct, edx) / sizeof(long),
+ [UNW_X86_ECX] = offsetof(struct user_regs_struct, ecx) / sizeof(long),
+ [UNW_X86_EBX] = offsetof(struct user_regs_struct, ebx) / sizeof(long),
+ [UNW_X86_ESI] = offsetof(struct user_regs_struct, esi) / sizeof(long),
+ [UNW_X86_EDI] = offsetof(struct user_regs_struct, edi) / sizeof(long),
+ [UNW_X86_EBP] = offsetof(struct user_regs_struct, ebp) / sizeof(long),
+ [UNW_X86_ESP] = offsetof(struct user_regs_struct, esp) / sizeof(long),
+ [UNW_X86_EIP] = offsetof(struct user_regs_struct, eip) / sizeof(long),
+ [UNW_X86_EFLAGS] = offsetof(struct user_regs_struct, eflags) /
sizeof(long),
+ [UNW_X86_TRAPNO] = offsetof(struct user_regs_struct, orig_eax) /
sizeof(long),
+ };
+#elif defined(UNW_TARGET_X86_64)
+ static const int8_t remap_regs[] =
+ {
+ [UNW_X86_RAX] = offsetof(struct user_regs_struct, rax) / sizeof(long),
+ [UNW_X86_RDX] = offsetof(struct user_regs_struct, rdx) / sizeof(long),
+ [UNW_X86_RCX] = offsetof(struct user_regs_struct, rcx) / sizeof(long),
+ [UNW_X86_RBX] = offsetof(struct user_regs_struct, rbx) / sizeof(long),
+ [UNW_X86_RSI] = offsetof(struct user_regs_struct, rsi) / sizeof(long),
+ [UNW_X86_RDI] = offsetof(struct user_regs_struct, rdi) / sizeof(long),
+ [UNW_X86_RBP] = offsetof(struct user_regs_struct, rbp) / sizeof(long),
+ [UNW_X86_RSP] = offsetof(struct user_regs_struct, rsp) / sizeof(long),
+ [UNW_X86_RIP] = offsetof(struct user_regs_struct, rip) / sizeof(long),
+ [UNW_X86_RFLAGS] = offsetof(struct user_regs_struct, rflags) /
sizeof(long),
+ [UNW_X86_TRAPNO] = offsetof(struct user_regs_struct, orig_rax) /
sizeof(long),
+ };
+#else
+#error Port me
+#endif
+
+ struct UCD_info *ui = arg;
+ if (regnum < 0 || regnum >= ARRAY_SIZE(remap_regs))
+ {
+ Debug(0, "%s: bad regnum:%d\n", __func__, regnum);
+ return -UNW_EINVAL;
+ }
+ regnum = remap_regs[regnum];
+
+ /* pr_reg is a long[] array, but it contains struct user_regs_struct's
+ * image.
+ */
+ Debug(1 "pr_reg[%d]:%ld (0x%lx)", regnum,
+ (long)ui->prstatus->pr_reg[regnum],
+ (long)ui->prstatus->pr_reg[regnum]
+ );
+ *valp = ui->prstatus->pr_reg[regnum];
+
+ return 0;
+}
diff -d -urpN libunwind.2/src/coredump/_UCD_create.c
libunwind.3/src/coredump/_UCD_create.c
--- libunwind.2/src/coredump/_UCD_create.c 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UCD_create.c 2012-02-21 18:03:23.400383339
+0100
@@ -0,0 +1,363 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+/* Endian detection */
+#include <limits.h>
+#include <byteswap.h>
+#include <endian.h>
+#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
+# define WE_ARE_BIG_ENDIAN 1
+# define WE_ARE_LITTLE_ENDIAN 0
+#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
+# define WE_ARE_BIG_ENDIAN 0
+# define WE_ARE_LITTLE_ENDIAN 1
+#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN
+# define WE_ARE_BIG_ENDIAN 1
+# define WE_ARE_LITTLE_ENDIAN 0
+#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN
+# define WE_ARE_BIG_ENDIAN 0
+# define WE_ARE_LITTLE_ENDIAN 1
+#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+# define WE_ARE_BIG_ENDIAN 1
+# define WE_ARE_LITTLE_ENDIAN 0
+#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
+# define WE_ARE_BIG_ENDIAN 0
+# define WE_ARE_LITTLE_ENDIAN 1
+#elif defined(__386__)
+# define WE_ARE_BIG_ENDIAN 0
+# define WE_ARE_LITTLE_ENDIAN 1
+#else
+# error "Can't determine endianness"
+#endif
+
+#include <elf.h>
+#include <sys/procfs.h> /* struct elf_prstatus */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+struct UCD_info *
+_UCD_create(const char *filename)
+{
+ union
+ {
+ Elf32_Ehdr h32;
+ Elf64_Ehdr h64;
+ } elf_header;
+#define elf_header32 elf_header.h32
+#define elf_header64 elf_header.h64
+ bool _64bits;
+
+ struct UCD_info *ui = memset(malloc(sizeof(*ui)), 0, sizeof(*ui));
+ ui->edi.di_cache.format = -1;
+ ui->edi.di_debug.format = -1;
+#if UNW_TARGET_IA64
+ ui->edi.ktab.format = -1;
+#endif
+
+ int fd = ui->coredump_fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto err;
+ ui->coredump_filename = strdup(filename);
+
+ /* No sane ELF32 file is going to be smaller then ELF64 _header_,
+ * so let's just read 64-bit sized one.
+ */
+ if (read(fd, &elf_header64, sizeof(elf_header64)) != sizeof(elf_header64))
+ {
+ Debug(0, "'%s' is not an ELF file\n", filename);
+ goto err;
+ }
+
+ if (memcmp(&elf_header32, "\x7f""ELF", 4) != 0)
+ {
+ Debug(0, "'%s' is not an ELF file\n", filename);
+ goto err;
+ }
+
+ if (elf_header32.e_ident[EI_CLASS] != ELFCLASS32
+ && elf_header32.e_ident[EI_CLASS] != ELFCLASS64)
+ {
+ Debug(0, "'%s' is not a 32/64 bit ELF file\n", filename);
+ goto err;
+ }
+
+ if (WE_ARE_LITTLE_ENDIAN != (elf_header32.e_ident[EI_DATA] == ELFDATA2LSB))
+ {
+ Debug(0, "'%s' is endian-incompatible\n", filename);
+ goto err;
+ }
+
+ _64bits = (elf_header32.e_ident[EI_CLASS] == ELFCLASS64);
+ if (_64bits && sizeof(elf_header64.e_entry) > sizeof(off_t))
+ {
+ Debug(0, "Can't process '%s': 64-bit file "
+ "while only %d bits are supported",
+ filename, 8 * sizeof(off_t));
+ goto err;
+ }
+
+ /* paranoia check */
+ if (_64bits
+ ? 0 /* todo: (elf_header64.e_ehsize != NN ||
elf_header64.e_phentsize != NN) */
+ : (elf_header32.e_ehsize != 52 || elf_header32.e_phentsize != 32)
+ )
+ {
+ Debug(0, "'%s' has wrong e_ehsize or e_phentsize\n", filename);
+ goto err;
+ }
+
+ off_t ofs = (_64bits ? elf_header64.e_phoff : elf_header32.e_phoff);
+ if (lseek(fd, ofs, SEEK_SET) != ofs)
+ {
+ Debug(0, "Can't read phdrs from '%s'\n", filename);
+ goto err;
+ }
+ unsigned size = ui->phdrs_count = (_64bits ? elf_header64.e_phnum :
elf_header32.e_phnum);
+ coredump_phdr_t *phdrs = ui->phdrs = memset(malloc(size * sizeof(phdrs[0])),
0, size * sizeof(phdrs[0]));
+ if (_64bits)
+ {
+ coredump_phdr_t *cur = phdrs;
+ unsigned i = 0;
+ while (i < size)
+ {
+ Elf64_Phdr hdr64;
+ if (read(fd, &hdr64, sizeof(hdr64)) != sizeof(hdr64))
+ {
+ Debug(0, "Can't read phdrs from '%s'\n", filename);
+ goto err;
+ }
+ cur->p_type = hdr64.p_type ;
+ cur->p_flags = hdr64.p_flags ;
+ cur->p_offset = hdr64.p_offset;
+ cur->p_vaddr = hdr64.p_vaddr ;
+ /*cur->p_paddr = hdr32.p_paddr ; always 0 */
+//TODO: check that and abort if it isn't?
+ cur->p_filesz = hdr64.p_filesz;
+ cur->p_memsz = hdr64.p_memsz ;
+ cur->p_align = hdr64.p_align ;
+ /* cur->backing_filename = NULL; - done by memset */
+ cur->backing_fd = -1;
+ cur->backing_filesize = hdr64.p_filesz;
+ i++;
+ cur++;
+ }
+ } else {
+ coredump_phdr_t *cur = phdrs;
+ unsigned i = 0;
+ while (i < size)
+ {
+ Elf32_Phdr hdr32;
+ if (read(fd, &hdr32, sizeof(hdr32)) != sizeof(hdr32))
+ {
+ Debug(0, "Can't read phdrs from '%s'\n", filename);
+ goto err;
+ }
+ cur->p_type = hdr32.p_type ;
+ cur->p_flags = hdr32.p_flags ;
+ cur->p_offset = hdr32.p_offset;
+ cur->p_vaddr = hdr32.p_vaddr ;
+ /*cur->p_paddr = hdr32.p_paddr ; always 0 */
+ cur->p_filesz = hdr32.p_filesz;
+ cur->p_memsz = hdr32.p_memsz ;
+ cur->p_align = hdr32.p_align ;
+ /* cur->backing_filename = NULL; - done by memset */
+ cur->backing_fd = -1;
+ cur->backing_filesize = hdr32.p_memsz;
+ i++;
+ cur++;
+ }
+ }
+
+ unsigned i = 0;
+ coredump_phdr_t *cur = phdrs;
+ while (i < size)
+ {
+ Debug(2, "phdr[%03d]: type:%d", i, cur->p_type);
+ if (cur->p_type == PT_NOTE)
+ {
+ ui->note_phdr = malloc(cur->p_filesz);
+ if (lseek(fd, cur->p_offset, SEEK_SET) != (off_t)cur->p_offset
+ || (uoff_t)read(fd, ui->note_phdr, cur->p_filesz) != cur->p_filesz
+ )
+ {
+ Debug(0, "Can't read PT_NOTE from '%s'\n", filename);
+ goto err;
+ }
+
+ /* Note is three 32-bit words: */
+ /* Elf32_Word n_namesz; Length of the note's name */
+ /* Elf32_Word n_descsz; Length of the note's descriptor */
+ /* Elf32_Word n_type; Type */
+ /* followed by name (padded to 32 bits(?)) and then descr */
+ Elf32_Nhdr *note_hdr = ui->note_phdr;
+ if (cur->p_filesz >= 3*4
+ && note_hdr->n_type == NT_PRSTATUS
+ && cur->p_filesz >= (3*4 + note_hdr->n_namesz + note_hdr->n_descsz +
sizeof(*ui->prstatus))
+ )
+ {
+ ui->prstatus = (void*) ((((long)note_hdr + sizeof(*note_hdr) +
note_hdr->n_namesz) + 3) & ~3L);
+#if 0
+ printf("pid:%d\n", ui->prstatus->pr_pid);
+ printf("ebx:%ld\n", (long)ui->prstatus->pr_reg[0]);
+ printf("ecx:%ld\n", (long)ui->prstatus->pr_reg[1]);
+ printf("edx:%ld\n", (long)ui->prstatus->pr_reg[2]);
+ printf("esi:%ld\n", (long)ui->prstatus->pr_reg[3]);
+ printf("edi:%ld\n", (long)ui->prstatus->pr_reg[4]);
+ printf("ebp:%ld\n", (long)ui->prstatus->pr_reg[5]);
+ printf("eax:%ld\n", (long)ui->prstatus->pr_reg[6]);
+ printf("xds:%ld\n", (long)ui->prstatus->pr_reg[7]);
+ printf("xes:%ld\n", (long)ui->prstatus->pr_reg[8]);
+ printf("xfs:%ld\n", (long)ui->prstatus->pr_reg[9]);
+ printf("xgs:%ld\n", (long)ui->prstatus->pr_reg[10]);
+ printf("orig_eax:%ld\n", (long)ui->prstatus->pr_reg[11]);
+#endif
+ }
+ }
+ if (cur->p_type == PT_LOAD)
+ {
+ Debug(2, " ofs:%08llx va:%08llx filesize:%08llx memsize:%08llx
flg:%x",
+ (unsigned long long) cur->p_offset,
+ (unsigned long long) cur->p_vaddr,
+ (unsigned long long) cur->p_filesz,
+ (unsigned long long) cur->p_memsz,
+ cur->p_flags
+ );
+ if (cur->p_filesz < cur->p_memsz)
+ Debug(2, " partial");
+ if (cur->p_flags & PF_X)
+ Debug(2, " executable");
+ }
+ Debug(2, "\n");
+ i++;
+ cur++;
+ }
+
+ if (!ui->prstatus)
+ {
+ Debug(0, "No NT_PRSTATUS note found in '%s'\n", filename);
+ goto err;
+ }
+
+ return ui;
+
+ err:
+ _UCD_destroy(ui);
+ return NULL;
+}
+
+int _UCD_add_backing_file(struct UCD_info *ui, int phdr_no, const char
*filename)
+{
+ if ((unsigned)phdr_no >= ui->phdrs_count)
+ {
+ Debug(0, "There is no segment %d in this coredump\n", phdr_no);
+ return -1;
+ }
+
+ struct coredump_phdr *phdr = &ui->phdrs[phdr_no];
+ if (phdr->backing_filename)
+ {
+ Debug(0, "Backing file already added to segment %d\n", phdr_no);
+ return -1;
+ }
+
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ Debug(0, "Can't open '%s'\n", filename);
+ return -1;
+ }
+
+ phdr->backing_fd = fd;
+ phdr->backing_filename = strdup(filename);
+
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) != 0)
+ {
+ Debug(0, "Can't stat '%s'\n", filename);
+ goto err;
+ }
+ phdr->backing_filesize = (uoff_t)statbuf.st_size;
+
+ if (phdr->p_flags != (PF_X | PF_R))
+ Debug(1, "Note: phdr[%u] is not r-x: flags are 0x%x\n", phdr_no,
phdr->p_flags);
+
+ if (phdr->backing_filesize > phdr->p_memsz)
+ {
+ /* This is expected */
+ Debug(2, "Note: phdr[%u] is %lld bytes, file is larger: %lld bytes\n",
+ phdr_no,
+ (unsigned long long)phdr->p_memsz,
+ (unsigned long long)phdr->backing_filesize
+ );
+ }
+//TODO: else loudly complain? Maybe even fail?
+
+ if (phdr->p_filesz != 0)
+ {
+//TODO: loop and compare in smaller blocks
+ char *core_buf = malloc(phdr->p_filesz);
+ char *file_buf = malloc(phdr->p_filesz);
+ if (lseek(ui->coredump_fd, phdr->p_offset, SEEK_SET) !=
(off_t)phdr->p_offset
+ || (uoff_t)read(ui->coredump_fd, core_buf, phdr->p_filesz) !=
phdr->p_filesz
+ )
+ {
+ Debug(0, "Error reading from coredump file\n");
+ err_read:
+ free(core_buf);
+ free(file_buf);
+ goto err;
+ }
+ if ((uoff_t)read(fd, file_buf, phdr->p_filesz) != phdr->p_filesz)
+ {
+ Debug(0, "Error reading from '%s'\n", filename);
+ goto err_read;
+ }
+ int r = memcmp(core_buf, file_buf, phdr->p_filesz);
+ free(core_buf);
+ free(file_buf);
+ if (r != 0)
+ {
+ Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file do not
match\n",
+ phdr_no, (unsigned long long)phdr->p_filesz
+ );
+ } else {
+ Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file
match\n",
+ phdr_no, (unsigned long long)phdr->p_filesz
+ );
+ }
+ }
+
+ /* Success */
+ return 0;
+
+ err:
+ if (phdr->backing_fd >= 0)
+ {
+ close(phdr->backing_fd);
+ phdr->backing_fd = -1;
+ }
+ free(phdr->backing_filename);
+ phdr->backing_filename = NULL;
+ return -1;
+}
diff -d -urpN libunwind.2/src/coredump/_UCD_destroy.c
libunwind.3/src/coredump/_UCD_destroy.c
--- libunwind.2/src/coredump/_UCD_destroy.c 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UCD_destroy.c 2012-02-21 18:03:23.400383339
+0100
@@ -0,0 +1,50 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_internal.h"
+
+void
+_UCD_destroy (struct UCD_info *ui)
+{
+ if (!ui)
+ return;
+
+ if (ui->coredump_fd >= 0)
+ close(ui->coredump_fd);
+ free(ui->coredump_filename);
+
+ invalidate_edi (&ui->edi);
+
+ unsigned i;
+ for (i = 0; i < ui->phdrs_count; i++)
+ {
+ struct coredump_phdr *phdr = &ui->phdrs[i];
+ free(phdr->backing_filename);
+ if (phdr->backing_fd >= 0)
+ close(phdr->backing_fd);
+ }
+
+ free(ui->note_phdr);
+
+ free(ui);
+}
diff -d -urpN libunwind.2/src/coredump/_UCD_find_proc_info.c
libunwind.3/src/coredump/_UCD_find_proc_info.c
--- libunwind.2/src/coredump/_UCD_find_proc_info.c 1970-01-01
01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UCD_find_proc_info.c 2012-02-21
18:03:23.401383333 +0100
@@ -0,0 +1,234 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include <elf.h>
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+static coredump_phdr_t *
+CD_elf_map_image(struct UCD_info *ui, coredump_phdr_t *phdr)
+{
+ struct elf_image *ei = &ui->edi.ei;
+
+ if (phdr->backing_fd < 0)
+ {
+ /* Note: coredump file contains only phdr->p_filesz bytes.
+ * We want to map bigger area (phdr->p_memsz bytes) to make sure
+ * these pages are allocated, but non-accessible.
+ */
+ /* addr, length, prot, flags, fd, fd_offset */
+ ei->image = mmap(NULL, phdr->p_memsz, PROT_READ, MAP_PRIVATE,
ui->coredump_fd, phdr->p_offset);
+ if (ei->image == MAP_FAILED)
+ {
+ ei->image = NULL;
+ return NULL;
+ }
+ ei->size = phdr->p_filesz;
+ size_t remainder_len = phdr->p_memsz - phdr->p_filesz;
+ if (remainder_len > 0)
+ {
+ void *remainder_base = (char*) ei->image + phdr->p_filesz;
+ munmap(remainder_base, remainder_len);
+ }
+ } else {
+ /* We have a backing file for this segment.
+ * This file is always longer than phdr->p_memsz,
+ * and if phdr->p_filesz !=0, first phdr->p_filesz bytes in coredump
+ * are the same as first bytes in the file. (Thus no need to map
coredump)
+ * We map the entire file:
+ * unwinding may need data which is past phdr->p_memsz bytes.
+ */
+ /* addr, length, prot, flags, fd, fd_offset */
+ ei->image = mmap(NULL, phdr->backing_filesize, PROT_READ, MAP_PRIVATE,
phdr->backing_fd, 0);
+ if (ei->image == MAP_FAILED)
+ {
+ ei->image = NULL;
+ return NULL;
+ }
+ ei->size = phdr->backing_filesize;
+ }
+
+ /* Check ELF header for sanity */
+ if (!elf_w(valid_object)(ei))
+ {
+ munmap(ei->image, ei->size);
+ ei->image = NULL;
+ ei->size = 0;
+ return NULL;
+ }
+
+ return phdr;
+}
+
+static coredump_phdr_t *
+CD_get_elf_image(struct UCD_info *ui, unw_word_t ip)
+{
+ unsigned i;
+ for (i = 0; i < ui->phdrs_count; i++)
+ {
+ coredump_phdr_t *phdr = &ui->phdrs[i];
+ if (phdr->p_vaddr <= ip && ip < phdr->p_vaddr + phdr->p_memsz)
+ {
+ phdr = CD_elf_map_image(ui, phdr);
+ return phdr;
+ }
+ }
+ return NULL;
+}
+
+static int
+get_unwind_info(struct UCD_info *ui, unw_addr_space_t as, unw_word_t ip)
+{
+ unsigned long segbase, mapoff;
+
+#if UNW_TARGET_IA64 && defined(__linux)
+ if (!ui->edi.ktab.start_ip && _Uia64_get_kernel_table (&ui->edi.ktab) < 0)
+ return -UNW_ENOINFO;
+
+ if (ui->edi.ktab.format != -1 && ip >= ui->edi.ktab.start_ip && ip <
ui->edi.ktab.end_ip)
+ return 0;
+#endif
+
+ if ((ui->edi.di_cache.format != -1
+ && ip >= ui->edi.di_cache.start_ip && ip < ui->edi.di_cache.end_ip)
+#if UNW_TARGET_ARM
+ || (ui->edi.di_debug.format != -1
+ && ip >= ui->edi.di_arm.start_ip && ip < ui->edi.di_arm.end_ip)
+#endif
+ || (ui->edi.di_debug.format != -1
+ && ip >= ui->edi.di_debug.start_ip && ip < ui->edi.di_debug.end_ip))
+ return 0;
+
+ invalidate_edi (&ui->edi);
+
+ /* Used to be tdep_get_elf_image() in ptrace unwining code */
+ coredump_phdr_t *phdr = CD_get_elf_image(ui, ip);
+ if (!phdr)
+ {
+ Debug(1, "%s returns error: CD_get_elf_image failed\n", __func__);
+ return -UNW_ENOINFO;
+ }
+ /* segbase: where it is mapped in virtual memory */
+ /* mapoff: offset in the file */
+ segbase = phdr->p_vaddr;
+ /*mapoff = phdr->p_offset; WRONG! phdr->p_offset is the offset in COREDUMP
file */
+ mapoff = 0;
+///FIXME. text segment is USUALLY, not always, at offset 0 in the binary/.so
file.
+// ensure that at initialization.
+
+ /* Here, SEGBASE is the starting-address of the (mmap'ped) segment
+ which covers the IP we're looking for. */
+ if (find_unwind_table(&ui->edi, as, phdr->backing_filename, segbase, mapoff,
ip) < 0)
+ {
+ Debug(1, "%s returns error: find_unwind_table failed\n", __func__);
+ return -UNW_ENOINFO;
+ }
+
+ /* This can happen in corner cases where dynamically generated
+ code falls into the same page that contains the data-segment
+ and the page-offset of the code is within the first page of
+ the executable. */
+ if (ui->edi.di_cache.format != -1
+ && (ip < ui->edi.di_cache.start_ip || ip >= ui->edi.di_cache.end_ip))
+ ui->edi.di_cache.format = -1;
+
+ if (ui->edi.di_debug.format != -1
+ && (ip < ui->edi.di_debug.start_ip || ip >= ui->edi.di_debug.end_ip))
+ ui->edi.di_debug.format = -1;
+
+ if (ui->edi.di_cache.format == -1
+#if UNW_TARGET_ARM
+ && ui->edi.di_arm.format == -1
+#endif
+ && ui->edi.di_debug.format == -1)
+ {
+ Debug(1, "%s returns error: all formats are -1\n", __func__);
+ return -UNW_ENOINFO;
+ }
+
+ Debug(1, "%s returns success\n", __func__);
+ return 0;
+}
+
+int
+_UCD_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct UCD_info *ui = arg;
+
+ Debug(1, "%s: entering\n", __func__);
+
+ int ret = -UNW_ENOINFO;
+
+ if (get_unwind_info(ui, as, ip) < 0) {
+ Debug(1, "%s returns error: get_unwind_info failed\n", __func__);
+ return -UNW_ENOINFO;
+ }
+
+#if UNW_TARGET_IA64
+ if (ui->edi.ktab.format != -1)
+ {
+ /* The kernel unwind table resides in local memory, so we have
+ to use the local address space to search it. Since
+ _UCD_put_unwind_info() has no easy way of detecting this
+ case, we simply make a copy of the unwind-info, so
+ _UCD_put_unwind_info() can always free() the unwind-info
+ without ill effects. */
+ ret = tdep_search_unwind_table (unw_local_addr_space, ip, &ui->edi.ktab,
pi,
+ need_unwind_info, arg);
+ if (ret >= 0)
+ {
+ if (!need_unwind_info)
+ pi->unwind_info = NULL;
+ else
+ {
+ void *mem = malloc (pi->unwind_info_size);
+
+ if (!mem)
+ return -UNW_ENOMEM;
+ memcpy (mem, pi->unwind_info, pi->unwind_info_size);
+ pi->unwind_info = mem;
+ }
+ }
+ }
+#endif
+
+ if (ret == -UNW_ENOINFO && ui->edi.di_cache.format != -1)
+ ret = tdep_search_unwind_table (as, ip, &ui->edi.di_cache,
+ pi, need_unwind_info, arg);
+
+#if UNW_TARGET_ARM
+ if (ret == -UNW_ENOINFO && ui->edi.di_arm.format != -1)
+ ret = tdep_search_unwind_table (as, ip, &ui->edi.di_arm, pi,
+ need_unwind_info, arg);
+#endif
+
+ if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1)
+ ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi,
+ need_unwind_info, arg);
+
+ Debug(1, "%s: returns %d\n", __func__, ret);
+
+ return ret;
+}
diff -d -urpN libunwind.2/src/coredump/_UCD_internal.h
libunwind.3/src/coredump/_UCD_internal.h
--- libunwind.2/src/coredump/_UCD_internal.h 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UCD_internal.h 2012-02-21 17:58:58.475519011
+0100
@@ -0,0 +1,91 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _UCD_internal_h
+#define _UCD_internal_h
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PROCFS_H
+#include <sys/procfs.h> /* struct elf_prstatus */
+#endif
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libunwind-coredump.h>
+
+#include "libunwind_i.h"
+
+
+#if SIZEOF_OFF_T == 4
+typedef uint32_t uoff_t;
+#elif SIZEOF_OFF_T == 8
+typedef uint64_t uoff_t;
+#else
+# error Unknown size of off_t!
+#endif
+
+
+/* Similar to ELF phdrs. p_paddr element is absent,
+ * since it's always 0 in coredumps.
+ */
+struct coredump_phdr
+ {
+ uint32_t p_type;
+ uint32_t p_flags;
+ uoff_t p_offset;
+ uoff_t p_vaddr;
+ uoff_t p_filesz;
+ uoff_t p_memsz;
+ uoff_t p_align;
+ /* Data for backing file. If backing_fd < 0, there is no file */
+ uoff_t backing_filesize;
+ char *backing_filename; /* for error meesages only */
+ int backing_fd;
+ };
+
+typedef struct coredump_phdr coredump_phdr_t;
+
+
+struct UCD_info
+ {
+ int big_endian; /* bool */
+ int coredump_fd;
+ char *coredump_filename; /* for error meesages only */
+ coredump_phdr_t *phdrs; /* array, allocated */
+ unsigned phdrs_count;
+ void *note_phdr; /* allocated or NULL */
+ struct elf_prstatus *prstatus; /* points inside note_phdr */
+
+ struct elf_dyn_info edi;
+ };
+
+#endif
diff -d -urpN libunwind.2/src/coredump/_UCD_lib.h
libunwind.3/src/coredump/_UCD_lib.h
--- libunwind.2/src/coredump/_UCD_lib.h 1970-01-01 01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UCD_lib.h 2012-02-21 17:58:41.578456227 +0100
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef _UCD_lib_h
+#define _UCD_lib_h
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <grp.h>
+#include <syslog.h>
+
+#endif
diff -d -urpN libunwind.2/src/coredump/_UPT_access_fpreg.c
libunwind.3/src/coredump/_UPT_access_fpreg.c
--- libunwind.2/src/coredump/_UPT_access_fpreg.c 1970-01-01
01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UPT_access_fpreg.c 2012-02-21
18:03:23.401383333 +0100
@@ -0,0 +1,34 @@
+/* libunwind - a platform-independent unwind library
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+int
+_UCD_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ print_error (__func__);
+ print_error (" not implemented\n");
+ return -UNW_EINVAL;
+}
diff -d -urpN libunwind.2/src/coredump/_UPT_elf.c
libunwind.3/src/coredump/_UPT_elf.c
--- libunwind.2/src/coredump/_UPT_elf.c 1970-01-01 01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UPT_elf.c 2012-02-21 18:03:23.401383333 +0100
@@ -0,0 +1,5 @@
+/* We need to get a separate copy of the ELF-code into
+ libunwind-ptrace since it cannot (and must not) have any ELF
+ dependencies on libunwind. */
+#include "libunwind_i.h" /* get ELFCLASS defined */
+#include "../elfxx.c"
diff -d -urpN libunwind.2/src/coredump/_UPT_get_dyn_info_list_addr.c
libunwind.3/src/coredump/_UPT_get_dyn_info_list_addr.c
--- libunwind.2/src/coredump/_UPT_get_dyn_info_list_addr.c 1970-01-01
01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UPT_get_dyn_info_list_addr.c 2012-02-21
18:03:23.401383333 +0100
@@ -0,0 +1,108 @@
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003-2005 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <address@hidden>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+#if UNW_TARGET_IA64 && defined(__linux)
+# include "elf64.h"
+# include "os-linux.h"
+
+static inline int
+get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
+ int *countp)
+{
+ unsigned long lo, hi, off;
+ struct UPT_info *ui = arg;
+ struct map_iterator mi;
+ char path[PATH_MAX];
+ unw_dyn_info_t *di;
+ unw_word_t res;
+ int count = 0;
+
+ maps_init (&mi, ui->pid);
+ while (maps_next (&mi, &lo, &hi, &off))
+ {
+ if (off)
+ continue;
+
+ invalidate_edi (&ui->edi);
+
+ if (elf_map_image (&ui->ei, path) < 0)
+ /* ignore unmappable stuff like "/SYSV00001b58 (deleted)" */
+ continue;
+
+ Debug (16, "checking object %s\n", path);
+
+ di = find_unwind_table (&ui->edi, as, path, lo, off);
+ if (di)
+ {
+ res = _Uia64_find_dyn_list (as, di, arg);
+ if (res && count++ == 0)
+ {
+ Debug (12, "dyn_info_list_addr = 0x%lx\n", (long) res);
+ *dil_addr = res;
+ }
+ }
+ }
+ maps_close (&mi);
+ *countp = count;
+ return 0;
+}
+
+#else
+
+static inline int
+get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
+ int *countp)
+{
+# warning Implement get_list_addr(), please.
+ *countp = 0;
+ return 0;
+}
+
+#endif
+
+int
+_UCD_get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dil_addr,
+ void *arg)
+{
+ int count, ret;
+
+ Debug (12, "looking for dyn_info list\n");
+
+ if ((ret = get_list_addr (as, dil_addr, arg, &count)) < 0)
+ return ret;
+
+ /* If multiple dynamic-info list addresses are found, we would have
+ to determine which was is the one actually in use (since the
+ dynamic name resolution algorithm will pick one "winner").
+ Perhaps we'd have to track them all until we find one that's
+ non-empty. Hopefully, this case simply will never arise, since
+ only libunwind defines the dynamic info list head. */
+ assert (count <= 1);
+
+ return (count > 0) ? 0 : -UNW_ENOINFO;
+}
diff -d -urpN libunwind.2/src/coredump/_UPT_get_proc_name.c
libunwind.3/src/coredump/_UPT_get_proc_name.c
--- libunwind.2/src/coredump/_UPT_get_proc_name.c 1970-01-01
01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UPT_get_proc_name.c 2012-02-21
18:03:23.401383333 +0100
@@ -0,0 +1,51 @@
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003 Hewlett-Packard Co
+ Copyright (C) 2007 David Mosberger-Tang
+ Contributed by David Mosberger-Tang <address@hidden>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+int
+_UCD_get_proc_name (unw_addr_space_t as, unw_word_t ip,
+ char *buf, size_t buf_len, unw_word_t *offp, void *arg)
+{
+ print_error (__func__);
+ print_error (" not implemented\n");
+ return -UNW_EINVAL;
+}
+
+#if 0
+{
+ struct UPT_info *ui = arg;
+
+#if ELF_CLASS == ELFCLASS64
+ return _Uelf64_get_proc_name (as, ui->pid, ip, buf, buf_len, offp);
+#elif ELF_CLASS == ELFCLASS32
+ return _Uelf32_get_proc_name (as, ui->pid, ip, buf, buf_len, offp);
+#else
+ return -UNW_ENOINFO;
+#endif
+}
+#endif
diff -d -urpN libunwind.2/src/coredump/_UPT_put_unwind_info.c
libunwind.3/src/coredump/_UPT_put_unwind_info.c
--- libunwind.2/src/coredump/_UPT_put_unwind_info.c 1970-01-01
01:00:00.000000000 +0100
+++ libunwind.3/src/coredump/_UPT_put_unwind_info.c 2012-02-21
18:03:23.401383333 +0100
@@ -0,0 +1,36 @@
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <address@hidden>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+void
+_UCD_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
+{
+ if (!pi->unwind_info)
+ return;
+ free (pi->unwind_info);
+ pi->unwind_info = NULL;
+}
diff -d -urpN libunwind.2/src/coredump/_UPT_resume.c
libunwind.3/src/coredump/_UPT_resume.c
--- libunwind.2/src/coredump/_UPT_resume.c 1970-01-01 01:00:00.000000000
+0100
+++ libunwind.3/src/coredump/_UPT_resume.c 2012-02-21 18:03:23.401383333
+0100
@@ -0,0 +1,35 @@
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <address@hidden>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "_UCD_lib.h"
+#include "_UCD_internal.h"
+
+int
+_UCD_resume (unw_addr_space_t as, unw_cursor_t *c, void *arg)
+{
+ print_error (__func__);
+ print_error (" not implemented\n");
+ return -UNW_EINVAL;
+}
diff -d -urpN libunwind.2/src/Makefile.am libunwind.3/src/Makefile.am
--- libunwind.2/src/Makefile.am 2012-02-21 17:57:16.863510404 +0100
+++ libunwind.3/src/Makefile.am 2012-02-21 17:58:41.579456231 +0100
@@ -8,7 +8,7 @@ COMMON_SO_LDFLAGS = -XCClinker -nostartf
lib_LIBRARIES =
lib_LTLIBRARIES =
if !REMOTE_ONLY
-lib_LIBRARIES += libunwind-ptrace.a
+lib_LIBRARIES += libunwind-ptrace.a libunwind-coredump.a
lib_LTLIBRARIES += libunwind.la
endif
@@ -26,6 +26,23 @@ libunwind_ptrace_a_SOURCES =
\
ptrace/_UPT_reg_offset.c ptrace/_UPT_resume.c
noinst_HEADERS += ptrace/_UPT_internal.h
+### libunwind-coredump:
+libunwind_coredump_a_SOURCES = \
+ coredump/_UCD_accessors.c \
+ coredump/_UCD_create.c \
+ coredump/_UCD_destroy.c \
+ coredump/_UCD_access_reg.c \
+ coredump/_UCD_access_mem.c \
+ coredump/_UCD_find_proc_info.c \
+ \
+ coredump/_UPT_elf.c \
+ coredump/_UPT_access_fpreg.c \
+ coredump/_UPT_get_dyn_info_list_addr.c \
+ coredump/_UPT_put_unwind_info.c \
+ coredump/_UPT_get_proc_name.c \
+ coredump/_UPT_resume.c
+noinst_HEADERS += coredump/_UCD_internal.h
+
### libunwind-setjmp:
libunwind_setjmp_la_LDFLAGS = $(COMMON_SO_LDFLAGS) \
-version-info $(SETJMP_SO_VERSION)