Libunwind generates backtraces much more reliably than glibc's "backtrace".
Signed-off-by: Marcin Slusarz <[email protected]> --- configure.ac | 7 +++++ include/dix-config.h.in | 3 +++ os/Makefile.am | 5 ++++ os/backtrace.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/configure.ac b/configure.ac index 9415a54..4a292da 100644 --- a/configure.ac +++ b/configure.ac @@ -309,6 +309,13 @@ AC_CHECK_HEADER([execinfo.h],[ ])] ) +PKG_CHECK_MODULES(LIBUNWIND, libunwind, [HAVE_LIBUNWIND=yes], [HAVE_LIBUNWIND=no]) +if test "x$HAVE_LIBUNWIND" = xyes; then + AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support]) +fi +AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$HAVE_LIBUNWIND" = xyes]) + + dnl --------------------------------------------------------------------------- dnl Bus options and CPU capabilities. Replaces logic in dnl hw/xfree86/os-support/bus/Makefile.am, among others. diff --git a/include/dix-config.h.in b/include/dix-config.h.in index 578f249..5102263 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -60,6 +60,9 @@ /* Has backtrace support */ #undef HAVE_BACKTRACE +/* Has libunwind support */ +#undef HAVE_LIBUNWIND + /* Define to 1 if you have the <byteswap.h> header file. */ #undef HAVE_BYTESWAP_H diff --git a/os/Makefile.am b/os/Makefile.am index 8891485..364b6da 100644 --- a/os/Makefile.am +++ b/os/Makefile.am @@ -34,6 +34,11 @@ if XDMCP libos_la_SOURCES += $(XDMCP_SRCS) endif +if HAVE_LIBUNWIND +AM_CFLAGS += $(LIBUNWIND_CFLAGS) +libos_la_LIBADD += $(LIBUNWIND_LIBS) +endif + EXTRA_DIST = $(SECURERPC_SRCS) $(XDMCP_SRCS) if SPECIAL_DTRACE_OBJECTS diff --git a/os/backtrace.c b/os/backtrace.c index daac60c..02aeb03 100644 --- a/os/backtrace.c +++ b/os/backtrace.c @@ -30,6 +30,75 @@ #include <errno.h> #include <string.h> +#ifdef HAVE_LIBUNWIND + +#define UNW_LOCAL_ONLY +#include <libunwind.h> + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <dlfcn.h> + +void +xorg_backtrace(void) +{ + unw_cursor_t cursor; + unw_context_t context; + unw_word_t off; + unw_proc_info_t pip; + int ret, i = 0; + char procname[256]; + const char *filename; + Dl_info dlinfo; + + pip.unwind_info = NULL; + ret = unw_getcontext(&context); + if (ret) { + ErrorFSigSafe("unw_getcontext: %d\n", ret); + return; + } + + ret = unw_init_local(&cursor, &context); + if (ret) { + ErrorFSigSafe("unw_init_local: %d\n", ret); + return; + } + + ErrorFSigSafe("\n"); + ErrorFSigSafe("Backtrace:\n"); + ret = unw_step(&cursor); + while (ret > 0) { + ret = unw_get_proc_info(&cursor, &pip); + if (ret) { + ErrorFSigSafe("unw_get_proc_info: %d\n", ret); + break; + } + + ret = unw_get_proc_name(&cursor, procname, 256, &off); + if (ret && ret != -UNW_ENOMEM) { + if (ret != -UNW_EUNSPEC) + ErrorFSigSafe("unw_get_proc_name: %d\n", ret); + procname[0] = '?'; + procname[1] = 0; + } + + if (dladdr((void *)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname && + *dlinfo.dli_fname) + filename = dlinfo.dli_fname; + else + filename = "?"; + + ErrorFSigSafe("%u: %s (%s%s+0x%x) [%p]\n", i++, filename, procname, + ret == -UNW_ENOMEM ? "..." : "", (int)off, (void *)(pip.start_ip + off)); + + ret = unw_step(&cursor); + if (ret < 0) + ErrorFSigSafe("unw_step: %d\n", ret); + } + ErrorFSigSafe("\n"); +} +#else #ifdef HAVE_BACKTRACE #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -246,3 +315,4 @@ xorg_backtrace(void) #endif #endif +#endif -- 1.8.1 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
