[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Libunwind-devel] [PATCH 2/2] coredump: add test
From: |
Martin Milata |
Subject: |
[Libunwind-devel] [PATCH 2/2] coredump: add test |
Date: |
Tue, 22 May 2012 11:51:07 +0200 |
Program test-coredump-unwind was modified to map backing files based on
virtual addresses instead of segment numbers.
The crasher.c is a program that calls some functions and then writes to
invalid address causing a crash.
The test itself is a shell script, which runs the program. The script
then tries to determine the virtual addresses based on output of 'ldd'
and 'readelf' and then runs test-coredump-unwind to check whether the
stack trace obtained from the dump roughly corresponds to what it should
look like.
Signed-off-by: Martin Milata <address@hidden>
---
.gitignore | 2 +
tests/Makefile.am | 18 +++++++-----
tests/crasher.c | 27 +++++++++++++++++++
tests/run-coredump-unwind | 30 +++++++++++++++++++++
tests/test-coredump-unwind.c | 60 +++++++++++++++++++++++++++++++++--------
5 files changed, 118 insertions(+), 19 deletions(-)
create mode 100644 tests/crasher.c
create mode 100755 tests/run-coredump-unwind
diff --git a/.gitignore b/.gitignore
index 62563e5..2f805cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,10 +38,12 @@ tests/Ltest-nomalloc
tests/Ltest-nocalloc
tests/Lperf-simple
tests/check-namespace.sh
+tests/crasher
tests/forker
tests/mapper
tests/rs-race
tests/test-async-sig
+tests/test-coredump-unwind
tests/test-flush-cache
tests/test-init-remote
tests/test-mem
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4b3bce3..6de90cd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,8 +1,8 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
EXTRA_DIST = run-ia64-test-dyn1 run-ptrace-mapper run-ptrace-misc \
- run-check-namespace check-namespace.sh.in Gtest-nomalloc.c \
- Gtest-nocalloc.c
+ run-check-namespace run-coredump-unwind \
+ check-namespace.sh.in Gtest-nomalloc.c Gtest-nocalloc.c
MAINTAINERCLEANFILES = Makefile.in
@@ -36,7 +36,8 @@ endif #USE_ALTIVEC
noinst_PROGRAMS_arch = $(noinst_PROGRAMS_arch_altivec) ppc64-test-wchar
endif #ARCH_PPC64
endif #ARCH_IA64
- check_SCRIPTS_cdep = run-ptrace-mapper run-ptrace-misc
+ check_SCRIPTS_cdep = run-ptrace-mapper run-ptrace-misc \
+ run-coredump-unwind
check_PROGRAMS_cdep = Gtest-bt Ltest-bt Gtest-exc Ltest-exc \
Gtest-init Ltest-init \
Gtest-concurrent Ltest-concurrent \
@@ -45,10 +46,9 @@ endif #ARCH_IA64
Gtest-trace Ltest-trace \
test-async-sig test-flush-cache test-init-remote \
test-mem test-setjmp test-ptrace \
- Ltest-nomalloc Ltest-nocalloc rs-race \
- test-coredump-unwind
- noinst_PROGRAMS_cdep = forker mapper test-ptrace-misc \
- Gperf-simple Lperf-simple
+ Ltest-nomalloc Ltest-nocalloc rs-race
+ noinst_PROGRAMS_cdep = forker crasher mapper test-ptrace-misc \
+ Gperf-simple Lperf-simple test-coredump-unwind
if HAVE_BACKTRACE
noinst_PROGRAMS_cdep += Gperf-trace Lperf-trace test-varargs
@@ -111,6 +111,10 @@ Ltest_nocalloc_SOURCES = Ltest-nocalloc.c
Gtest_trace_SOURCES = Gtest-trace.c ident.c
Ltest_trace_SOURCES = Ltest-trace.c ident.c
+# prevent function inlining
+crasher: crasher.c
+ $(CC) -O0 -o crasher crasher.c
+
LIBUNWIND = $(top_builddir)/src/libunwind-$(arch).la
LIBUNWIND_ptrace = $(top_builddir)/src/libunwind-ptrace.a
LIBUNWIND_coredump = $(top_builddir)/src/libunwind-coredump.a
diff --git a/tests/crasher.c b/tests/crasher.c
new file mode 100644
index 0000000..fbee0d5
--- /dev/null
+++ b/tests/crasher.c
@@ -0,0 +1,27 @@
+/* This program should crash and produce coredump */
+
+#include <stdio.h>
+
+void a(void) __attribute__((noinline));
+void b(int x) __attribute__((noinline));
+
+void a(void)
+{
+ *(int *)NULL = 42;
+}
+
+void b(int x)
+{
+ if (x)
+ a();
+ else
+ b(1);
+}
+
+int
+main (int argc, char **argv)
+{
+ b(0);
+ return 0;
+}
+
diff --git a/tests/run-coredump-unwind b/tests/run-coredump-unwind
new file mode 100755
index 0000000..4c6dbc4
--- /dev/null
+++ b/tests/run-coredump-unwind
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+TESTDIR=`pwd`
+TEMPDIR=`mktemp -d`
+
+# create core dump
+cd $TEMPDIR
+(
+ ulimit -c 10000
+ $TESTDIR/crasher
+) 2>/dev/null
+COREFILE=$TEMPDIR/core*
+cd $TESTDIR
+
+# fail if any command fails
+set -e
+
+# find out where to map shared libraries
+BACKING=""
+for LINE in `ldd crasher | sed -nre 's#^[^/]*(/[^ ]+)[
]+\((.[^)]*)\).*$#\2:\1#p'`; do
+ BACKING="$BACKING $LINE"
+done
+
+# find the base address of the binary
+BASE=`readelf -l crasher | grep LOAD | head -n1 | sed -re 's#^.*LOAD[^0]+0x[^
]+[^0]+(0x[^ ]+).*$#\1#'`
+
+# magic option -testcase enables checking for the specific contents of the
stack
+./test-coredump-unwind $COREFILE -testcase $BASE:crasher $BACKING
+
+rm -r -- $TEMPDIR
diff --git a/tests/test-coredump-unwind.c b/tests/test-coredump-unwind.c
index 54fba57..7197e76 100644
--- a/tests/test-coredump-unwind.c
+++ b/tests/test-coredump-unwind.c
@@ -10,11 +10,13 @@
* -oexample-core-unwind
*
* Run:
- * objdump -sx COREDUMP
* eu-unstrip -n --core COREDUMP
- * figure out which segments in COREDUMP correspond to which mapped
executable files
+ * figure out which virtual addresses 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 [...]
+ * ./example-core-unwind COREDUMP 0x400000:/bin/crashed_program
0x3458600000:/lib/libc.so.6 [...]
+ *
+ * Note: Program eu-unstrip is part of elfutils, virtual addresses of shared
+ * libraries can be determined by ldd (at least on linux).
*/
#undef _GNU_SOURCE
@@ -256,6 +258,11 @@ main(int argc, char **argv)
unw_cursor_t c;
int ret;
+#define TEST_FRAMES 4
+ int testcase = 0;
+ int test_cur = 0;
+ long test_start_ips[TEST_FRAMES];
+
install_sigsegv_handler();
const char *progname = strrchr(argv[0], '/');
@@ -265,7 +272,7 @@ main(int argc, char **argv)
progname = argv[0];
if (!argv[1])
- error_msg_and_die("Usage: %s COREDUMP [SEGMENT_NO:BINARY_FILE]...",
progname);
+ error_msg_and_die("Usage: %s COREDUMP [VADDR:BINARY_FILE]...", progname);
msg_prefix = progname;
@@ -281,16 +288,23 @@ main(int argc, char **argv)
error_msg_and_die("unw_init_remote() failed: ret=%d\n", ret);
argv += 2;
+
+ /* Enable checks for the crasher test program? */
+ if (*argv && !strcmp(*argv, "-testcase"))
+ {
+ testcase = 1;
+ logmode = LOGMODE_NONE;
+ argv++;
+ }
+
while (*argv)
{
- char *colon = strchr(*argv, ':');
- if (!colon)
+ char *colon;
+ long vaddr = strtol(*argv, &colon, 16);
+ if (*colon != ':')
error_msg_and_die("Bad format: '%s'", *argv);
- *colon = '\0';
- unsigned n = atoi(*argv);
- *colon = ':';
- if (_UCD_add_backing_file_at_segment(ui, n, colon + 1) < 0)
- error_msg_and_die("Can't add backing file '%s'", *argv);
+ if (_UCD_add_backing_file_at_vaddr(ui, vaddr, colon + 1) < 0)
+ error_msg_and_die("Can't add backing file '%s'", colon + 1);
argv++;
}
@@ -305,11 +319,19 @@ main(int argc, char **argv)
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",
+
+ if (!testcase)
+ 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);
+ if (testcase && test_cur < TEST_FRAMES)
+ {
+ test_start_ips[test_cur] = (long) pi.start_ip;
+ test_cur++;
+ }
+
log("step");
ret = unw_step(&c);
log("step done:%d", ret);
@@ -320,6 +342,20 @@ main(int argc, char **argv)
}
log("stepping ended");
+ /* Check that the second and third frames are equal, but distinct of the
+ * others */
+ if (testcase &&
+ (test_cur != 4
+ || test_start_ips[1] != test_start_ips[2]
+ || test_start_ips[0] == test_start_ips[1]
+ || test_start_ips[2] == test_start_ips[3]
+ )
+ )
+ {
+ fprintf(stderr, "FAILURE: start IPs incorrect\n");
+ return -1;
+ }
+
_UCD_destroy(ui);
return 0;
--
1.7.7.6