diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | common.h | 10 | ||||
-rw-r--r-- | configure.ac | 26 | ||||
-rw-r--r-- | execute_program.c | 8 | ||||
-rw-r--r-- | options.c | 18 | ||||
-rw-r--r-- | options.h | 3 | ||||
-rw-r--r-- | output.c | 22 | ||||
-rw-r--r-- | proc.c | 17 |
9 files changed, 118 insertions, 0 deletions
@@ -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 @@ -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; } @@ -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) { @@ -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; @@ -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; } @@ -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; } |