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 <marcin.slusarz@gmail.com>
This commit is contained in:
Marcin Slusarz 2013-02-18 13:27:22 -05:00 committed by Kristian Høgsberg
parent 1cc9e08d2f
commit 554a0da74a
3 changed files with 92 additions and 11 deletions

View File

@ -281,6 +281,13 @@ if test "x$GCC" = "xyes"; then
fi fi
AC_SUBST(GCC_CFLAGS) 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 if test "x$WESTON_NATIVE_BACKEND" = "x"; then
WESTON_NATIVE_BACKEND="drm-backend.so" WESTON_NATIVE_BACKEND="drm-backend.so"
fi fi

View File

@ -8,8 +8,9 @@ AM_CPPFLAGS = \
-DIN_WESTON -DIN_WESTON
weston_LDFLAGS = -export-dynamic weston_LDFLAGS = -export-dynamic
weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS)
weston_LDADD = $(COMPOSITOR_LIBS) $(DLOPEN_LIBS) -lm ../shared/libshared.la weston_LDADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \
$(DLOPEN_LIBS) -lm ../shared/libshared.la
weston_SOURCES = \ weston_SOURCES = \
git-version.h \ git-version.h \

View File

@ -49,6 +49,11 @@
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#ifdef HAVE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#endif
#include <wayland-server.h> #include <wayland-server.h>
#include "compositor.h" #include "compositor.h"
#include "../shared/os-compatibility.h" #include "../shared/os-compatibility.h"
@ -3051,13 +3056,88 @@ static int on_term_signal(int signal_number, void *data)
return 1; return 1;
} }
#ifdef HAVE_LIBUNWIND
static void 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]; void *buffer[32];
int i, count; int i, count;
Dl_info info; 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 /* This SIGSEGV handler will do a best-effort backtrace, and
* then call the backend restore function, which will switch * then call the backend restore function, which will switch
* back to the vt we launched from or ungrab X etc and then * 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"); weston_log("caught segv\n");
count = backtrace(buffer, ARRAY_LENGTH(buffer)); print_backtrace();
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);
}
segv_compositor->restore(segv_compositor); segv_compositor->restore(segv_compositor);