[PATCH] os: use libunwind to generate backtraces

Peter Hutterer peter.hutterer at who-t.net
Wed Feb 20 15:37:30 PST 2013


On Tue, Feb 19, 2013 at 09:29:03PM +0100, Marcin Slusarz wrote:
[...]
> ---
> From: Marcin Slusarz <marcin.slusarz at gmail.com>
> Subject: [PATCH] os: use libunwind to generate backtraces
> 
> Libunwind generates backtraces much more reliably than glibc's "backtrace".
> 
> Before:
> 0: /opt/xserver/bin/X (0x400000+0x18ce36) [0x58ce36]
> 1: /opt/xserver/bin/X (xorg_backtrace+0x9) [0x58d119]
> 2: /opt/xserver/bin/X (0x400000+0x190d69) [0x590d69]
> 3: /lib64/libpthread.so.0 (0x7fb904268000+0x10a90) [0x7fb904278a90]
> 4: /lib64/libc.so.6 (ioctl+0x7) [0x7fb902fbf987]
> 5: /usr/lib64/libdrm.so.2 (drmIoctl+0x28) [0x7fb90405ffa8]
> 6: /usr/lib64/libdrm.so.2 (drmCommandWrite+0x1b) [0x7fb90406235b]
> 7: /usr/lib64/libdrm_nouveau.so.2 (nouveau_bo_wait+0x89) [0x7fb902009719]
> 8: /opt/xserver/lib/xorg/modules/drivers/nouveau_drv.so (0x7fb90220e000+0x76f3) [0x7fb9022156f3]
> 9: /opt/xserver/lib/xorg/modules/libexa.so (0x7fb9019c7000+0xbae0) [0x7fb9019d2ae0]
> 10: /opt/xserver/bin/X (0x400000+0x17d2b3) [0x57d2b3]
> 11: /opt/xserver/bin/X (0x400000+0xc9930) [0x4c9930]
> 12: /opt/xserver/bin/X (0x400000+0x3a81a) [0x43a81a]
> 13: /opt/xserver/bin/X (0x400000+0x3d6a1) [0x43d6a1]
> 14: /opt/xserver/bin/X (0x400000+0x2c2ca) [0x42c2ca]
> 15: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x7fb902f019b5]
> 16: /opt/xserver/bin/X (0x400000+0x2c60d) [0x42c60d]
> 17: ?? [0x0]
> 
> After:
> 0: /opt/xserver/bin/X (OsSigHandler+0x39) [0x590d69]
> 1: /lib64/libpthread.so.0 (__restore_rt+0x0) [0x7fb904278a8f]
> 2: /lib64/libc.so.6 (ioctl+0x7) [0x7fb902fbf987]
> 3: /usr/lib64/libdrm.so.2 (drmIoctl+0x28) [0x7fb90405ffa8]
> 4: /usr/lib64/libdrm.so.2 (drmCommandWrite+0x1b) [0x7fb90406235b]
> 5: /usr/lib64/libdrm_nouveau.so.2 (nouveau_bo_wait+0x89) [0x7fb902009719]
> 6: /opt/xserver/lib/xorg/modules/drivers/nouveau_drv.so (nouveau_exa_download_from_screen+0x1a3) [0x7fb9022156f3]
> 7: /opt/xserver/lib/xorg/modules/libexa.so (exaGetImage+0x1f0) [0x7fb9019d2ae0]
> 8: /opt/xserver/bin/X (miSpriteGetImage+0x173) [0x57d2b3]
> 9: /opt/xserver/bin/X (compGetImage+0xb0) [0x4c9930]
> 10: /opt/xserver/bin/X (ProcGetImage+0x55a) [0x43a81a]
> 11: /opt/xserver/bin/X (Dispatch+0x341) [0x43d6a1]
> 12: /opt/xserver/bin/X (main+0x3ba) [0x42c2ca]
> 13: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x7fb902f019b5]
> 14: /opt/xserver/bin/X (_start+0x29) [0x42c60d]
> 15: ? (?+0x29) [0x29]
> 
> Signed-off-by: Marcin Slusarz <marcin.slusarz at gmail.com>
> ---
>  configure.ac            |  7 +++++
>  include/dix-config.h.in |  3 ++
>  os/Makefile.am          |  5 ++++
>  os/backtrace.c          | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 90 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..426f9b1 100644
> --- a/os/backtrace.c
> +++ b/os/backtrace.c
> @@ -30,6 +30,80 @@
>  #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 failed: %s [%d]\n", unw_strerror(ret),
> +                ret);
> +        return;
> +    }
> +
> +    ret = unw_init_local(&cursor, &context);
> +    if (ret) {
> +        ErrorFSigSafe("unw_init_local failed: %s [%d]\n", unw_strerror(ret),
> +                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 failed: %s [%d]\n",
> +                    unw_strerror(ret), 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 failed: %s [%d]\n",
> +                        unw_strerror(ret), 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 failed: %s [%d]\n", unw_strerror(ret), ret);
> +    }
> +    ErrorFSigSafe("\n");
> +}
> +#else /* HAVE_LIBUNWIND */
>  #ifdef HAVE_BACKTRACE
>  #ifndef _GNU_SOURCE
>  #define _GNU_SOURCE
> @@ -246,3 +320,4 @@ xorg_backtrace(void)
>  
>  #endif
>  #endif
> +#endif
> -- 
> 1.8.1

thanks for the changes but after applying this patch locally I do wonder:
how did you test this? i'm getting undefined references to the various
libunwind calls (_Ux86_64_getcontext, _Ux86_64_strerror,etc) for Xvfb, Xdmx, Xnext
and all the tests). This needs some more polishing.

Cheers,
   Peter



More information about the xorg-devel mailing list