aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--Makefile.am3
-rw-r--r--common.h10
-rw-r--r--configure.ac26
-rw-r--r--execute_program.c8
-rw-r--r--options.c18
-rw-r--r--options.h3
-rw-r--r--output.c22
-rw-r--r--proc.c17
9 files changed, 118 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index db1db7b..97c3573 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2010-10-31 Joe Damato <ice799@gmail.com>
+
+ * Makefile.am: Add autotool support for libunwind.
+ * configure.ac: Ditto.
+ * common.h: New structure fields for libunwind.
+ * execute_program.c: Initialize libunwind.
+ * proc.c: Ditto.
+ * options.c: New command line option (-w).
+ * options.h: New options parameter for libunwind.
+ * output.c: Use libunwind to do backtraces.
+
2010-10-18 Petr Machata <pmachata@redhat.com>
* sysdeps/linux-gnu/s390/trace.c: Support 5th argument fetching on s390.
diff --git a/Makefile.am b/Makefile.am
index 994a4b5..e6d24b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,6 +28,9 @@ libltrace_la_LIBADD = \
$(libelf_LIBS) \
$(liberty_LIBS) \
$(libsupcxx_LIBS) \
+ $(libunwind_LIBS) \
+ $(libunwind_ptrace_LIBS) \
+ $(libunwind_arch_LIBS) \
sysdeps/libos.la
diff --git a/common.h b/common.h
index 351ff80..20f1a96 100644
--- a/common.h
+++ b/common.h
@@ -1,3 +1,7 @@
+#if defined(HAVE_LIBUNWIND)
+#include <libunwind.h>
+#endif /* defined(HAVE_LIBUNWIND) */
+
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
@@ -186,6 +190,12 @@ struct Process {
/* output: */
enum tof type_being_displayed;
+#if defined(HAVE_LIBUNWIND)
+ /* libunwind address space */
+ unw_addr_space_t unwind_as;
+ void *unwind_priv;
+#endif /* defined(HAVE_LIBUNWIND) */
+
Process * next;
};
diff --git a/configure.ac b/configure.ac
index 4838479..dd330ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,6 +62,32 @@ AC_CHECK_LIB([supc++], [__cxa_demangle], [
AC_SUBST(libsupcxx_LIBS)
+# HAVE_LIBUNWIND
+AC_ARG_WITH(libunwind,
+[ --with-libunwind Use libunwind frame unwinding support],
+[case "${withval}" in
+ yes) enable_libunwind=yes ;;
+ no) enable_libunwind=no ;;
+ *) AC_MSG_ERROR(bad value ${withval} for GDB with-libunwind option) ;;
+esac],[
+ AC_CHECK_HEADERS(libunwind.h)
+ AC_CHECK_HEADERS(libunwind-ptrace.h)
+ if test x"$ac_cv_header_libunwind_h" = xyes; then
+ enable_libunwind=yes;
+ fi
+])
+
+if test x"$enable_libunwind" = xyes; then
+ AC_CHECK_LIB(unwind, backtrace, libunwind_LIBS=-lunwind, libunwind_LIBS=)
+ AC_SUBST(libunwind_LIBS)
+ AC_CHECK_LIB(unwind-ptrace, _UPT_create, libunwind_ptrace_LIBS=-lunwind-ptrace, libunwind_ptrace_LIBS=)
+ AC_SUBST(libunwind_ptrace_LIBS)
+ AC_CHECK_LIB(unwind-${HOST_CPU}, _U${HOST_CPU}_init_remote, libunwind_arch_LIBS=-lunwind-${HOST_CPU}, libunwind_arch_LIBS=)
+ AC_SUBST(libunwind_arch_LIBS)
+ AC_DEFINE([HAVE_LIBUNWIND], [1], [we have libunwind])
+fi
+
+
# HAVE_ELF_C_READ_MMAP
AC_MSG_CHECKING([whether elf_begin accepts ELF_C_READ_MMAP])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <gelf.h>]], [[
diff --git a/execute_program.c b/execute_program.c
index 5fd6379..3651b66 100644
--- a/execute_program.c
+++ b/execute_program.c
@@ -1,5 +1,9 @@
#include "config.h"
+#if defined(HAVE_LIBUNWIND)
+#include <libunwind-ptrace.h>
+#endif /* defined(HAVE_LIBUNWIND) */
+
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -87,5 +91,9 @@ execute_program(Process *sp, char **argv) {
sp->pid = pid;
+#if defined(HAVE_LIBUNWIND)
+ sp->unwind_priv = _UPT_create(pid);
+#endif /* defined(HAVE_LIBUNWIND) */
+
return;
}
diff --git a/options.c b/options.c
index 8589572..54f7338 100644
--- a/options.c
+++ b/options.c
@@ -100,6 +100,9 @@ usage(void) {
" -T show the time spent inside each call.\n"
" -u USERNAME run command with the userid, groupid of username.\n"
" -V, --version output version information and exit.\n"
+#if defined(HAVE_LIBUNWIND)
+ " -w=NR, --where=NR print backtrace showing NR stack frames at most.\n"
+#endif /* defined(HAVE_LIBUNWIND) */
" -x NAME treat the global NAME like a library subroutine.\n"
#ifdef PLT_REINITALISATION_BP
" -X NAME same as -x; and PLT's will be initialized by here.\n"
@@ -183,6 +186,9 @@ process_options(int argc, char **argv) {
options.output = stderr;
options.no_plt = 0;
options.no_signals = 0;
+#if defined(HAVE_LIBUNWIND)
+ options.bt_depth = -1;
+#endif /* defined(HAVE_LIBUNWIND) */
guess_cols();
@@ -204,13 +210,20 @@ process_options(int argc, char **argv) {
{"version", 0, 0, 'V'},
{"no-plt", 0, 0, 'g'},
{"no-signals", 0, 0, 'b'},
+#if defined(HAVE_LIBUNWIND)
+ {"where", 1, 0, 'w'},
+#endif /* defined(HAVE_LIBUNWIND) */
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "+cfhiLrStTVgb"
# ifdef USE_DEMANGLE
"C"
# endif
+#if defined(HAVE_LIBUNWIND)
+ "a:A:D:e:F:l:n:o:p:s:u:x:X:w:", long_options,
+#else /* !defined(HAVE_LIBUNWIND) */
"a:A:D:e:F:l:n:o:p:s:u:x:X:", long_options,
+#endif
&option_index);
if (c == -1) {
break;
@@ -313,6 +326,11 @@ process_options(int argc, char **argv) {
case 'n':
options.indent = atoi(optarg);
break;
+#if defined(HAVE_LIBUNWIND)
+ case 'w':
+ options.bt_depth = atoi(optarg);
+ break;
+#endif /* defined(HAVE_LIBUNWIND) */
case 'o':
options.output = fopen(optarg, "w");
if (!options.output) {
diff --git a/options.h b/options.h
index e2d0e7f..d171c4b 100644
--- a/options.h
+++ b/options.h
@@ -16,6 +16,9 @@ struct options_t {
int follow; /* trace child processes */
int no_plt; /* set bps on PLT entries */
int no_signals; /* don't print signals */
+#if defined(HAVE_LIBUNWIND)
+ int bt_depth; /* how may levels of stack frames to show */
+#endif /* defined(HAVE_LIBUNWIND) */
};
extern struct options_t options;
diff --git a/output.c b/output.c
index 37add02..de2a836 100644
--- a/output.c
+++ b/output.c
@@ -297,6 +297,28 @@ output_right(enum tof type, Process *proc, char *function_name) {
(int)current_time_spent.tv_usec);
}
fprintf(options.output, "\n");
+
+#if defined(HAVE_LIBUNWIND)
+ if (options.bt_depth > 0) {
+ unw_cursor_t cursor;
+ unw_word_t ip, sp;
+ int unwind_depth = options.bt_depth;
+ char fn_name[100];
+
+ unw_init_remote(&cursor, proc->unwind_as, proc->unwind_priv);
+ while (unwind_depth) {
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+ unw_get_proc_name(&cursor, fn_name, 100, NULL);
+ fprintf(options.output, "\t\t\t%s (ip = 0x%lx)\n", fn_name, (long) ip);
+ if (unw_step(&cursor) <= 0)
+ break;
+ unwind_depth--;
+ }
+ fprintf(options.output, "\n");
+ }
+#endif /* defined(HAVE_LIBUNWIND) */
+
current_proc = 0;
current_column = 0;
}
diff --git a/proc.c b/proc.c
index bfc6e41..1c57532 100644
--- a/proc.c
+++ b/proc.c
@@ -1,3 +1,10 @@
+#include "config.h"
+
+#if defined(HAVE_LIBUNWIND)
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+#endif /* defined(HAVE_LIBUNWIND) */
+
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
@@ -18,11 +25,21 @@ open_program(char *filename, pid_t pid) {
proc->breakpoints_enabled = -1;
if (pid) {
proc->pid = pid;
+#if defined(HAVE_LIBUNWIND)
+ proc->unwind_priv = _UPT_create(pid);
+ } else {
+ proc->unwind_priv = NULL;
+#endif /* defined(HAVE_LIBUNWIND) */
}
+
breakpoints_init(proc);
proc->next = list_of_processes;
list_of_processes = proc;
+
+#if defined(HAVE_LIBUNWIND)
+ proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0);
+#endif /* defined(HAVE_LIBUNWIND) */
return proc;
}