From 554a0da74a3f6fc945503a3eb1bfcc9038441b39 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Mon, 18 Feb 2013 13:27:22 -0500 Subject: [PATCH] compositor: Use libunwind if available for better backtraces libunwind has a dwarf parser and automatically queries the dlinfo for location of dlopened modules. The resulting backtrace is much better and includes stack frames in dynamically loaded modules. krh: Originally submitted for Xorg, adapted for weston: http://lists.x.org/archives/xorg-devel/2013-February/035493.html Note this require libunwind at least 1.1 to get the pkg-config files. Signed-off-by: Marcin Slusarz --- configure.ac | 7 ++++ src/Makefile.am | 5 +-- src/compositor.c | 91 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 32fbb4bd..e613aa05 100644 --- a/configure.ac +++ b/configure.ac @@ -281,6 +281,13 @@ if test "x$GCC" = "xyes"; then fi AC_SUBST(GCC_CFLAGS) +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]) + if test "x$WESTON_NATIVE_BACKEND" = "x"; then WESTON_NATIVE_BACKEND="drm-backend.so" fi diff --git a/src/Makefile.am b/src/Makefile.am index cfb072ec..a5e7dcf4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,8 +8,9 @@ AM_CPPFLAGS = \ -DIN_WESTON weston_LDFLAGS = -export-dynamic -weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) -weston_LDADD = $(COMPOSITOR_LIBS) $(DLOPEN_LIBS) -lm ../shared/libshared.la +weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS) +weston_LDADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \ + $(DLOPEN_LIBS) -lm ../shared/libshared.la weston_SOURCES = \ git-version.h \ diff --git a/src/compositor.c b/src/compositor.c index 63fe793e..5c19d92f 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -49,6 +49,11 @@ #include #include +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include +#endif + #include #include "compositor.h" #include "../shared/os-compatibility.h" @@ -3051,13 +3056,88 @@ static int on_term_signal(int signal_number, void *data) return 1; } +#ifdef HAVE_LIBUNWIND + static void -on_segv_signal(int s, siginfo_t *siginfo, void *context) +print_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) { + weston_log("unw_getcontext: %d\n", ret); + return; + } + + ret = unw_init_local(&cursor, &context); + if (ret) { + weston_log("unw_init_local: %d\n", ret); + return; + } + + ret = unw_step(&cursor); + while (ret > 0) { + ret = unw_get_proc_info(&cursor, &pip); + if (ret) { + weston_log("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) + weston_log("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 = "?"; + + weston_log("%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) + weston_log("unw_step: %d\n", ret); + } +} + +#else + +static void +print_backtrace(void) { void *buffer[32]; int i, count; Dl_info info; + count = backtrace(buffer, ARRAY_LENGTH(buffer)); + for (i = 0; i < count; i++) { + dladdr(buffer[i], &info); + weston_log(" [%016lx] %s (%s)\n", + (long) buffer[i], + info.dli_sname ? info.dli_sname : "--", + info.dli_fname); + } +} + +#endif + +static void +on_segv_signal(int s, siginfo_t *siginfo, void *context) +{ /* This SIGSEGV handler will do a best-effort backtrace, and * then call the backend restore function, which will switch * back to the vt we launched from or ungrab X etc and then @@ -3068,14 +3148,7 @@ on_segv_signal(int s, siginfo_t *siginfo, void *context) weston_log("caught segv\n"); - count = backtrace(buffer, ARRAY_LENGTH(buffer)); - for (i = 0; i < count; i++) { - dladdr(buffer[i], &info); - weston_log(" [%016lx] %s (%s)\n", - (long) buffer[i], - info.dli_sname ? info.dli_sname : "--", - info.dli_fname); - } + print_backtrace(); segv_compositor->restore(segv_compositor);