gallium/util: libunwind support
authorRob Clark <robdclark@gmail.com>
Fri, 24 Mar 2017 20:07:03 +0000 (16:07 -0400)
committerRob Clark <robdclark@gmail.com>
Mon, 3 Apr 2017 15:32:17 +0000 (11:32 -0400)
It's kinda sad that (a) we don't have debug_backtrace support on !X86
and that (b) we re-invent our own crude backtrace support in the first
place.  If available, use libunwind instead.  The backtrace format is
based on what xserver and weston use, since it is nice not to have to
figure out a different format.

Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
configure.ac
src/gallium/Automake.inc
src/gallium/auxiliary/util/u_debug_stack.c
src/gallium/auxiliary/util/u_debug_stack.h

index 70885fb9a6bf801157d36a8a628b2e2e1dc15d52..016e38fb5998e485332feed42679b1974ef382e9 100644 (file)
@@ -1025,6 +1025,30 @@ AC_SUBST([LLVM_LIBS])
 AC_SUBST([LLVM_LDFLAGS])
 AC_SUBST([LLVM_INCLUDEDIR])
 
+dnl
+dnl libunwind
+dnl
+AC_ARG_ENABLE([libunwind],
+    [AS_HELP_STRING([--enable-libunwind],
+            [Use libunwind for backtracing (default: auto)])],
+        [LIBUNWIND="$enableval"],
+        [LIBUNWIND="auto"])
+
+PKG_CHECK_MODULES(LIBUNWIND, libunwind, [HAVE_LIBUNWIND=yes], [HAVE_LIBUNWIND=no])
+if test "x$LIBUNWIND" = "xauto"; then
+    LIBUNWIND="$HAVE_LIBUNWIND"
+fi
+
+if test "x$LIBUNWIND" = "xyes"; then
+    if test "x$HAVE_LIBUNWIND" != "xyes"; then
+        AC_MSG_ERROR([libunwind requested but not installed.])
+    fi
+    AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
+fi
+
+AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$LIBUNWIND" = xyes])
+
+
 dnl Options for APIs
 AC_ARG_ENABLE([opengl],
     [AS_HELP_STRING([--disable-opengl],
index a01fa54053149372a32ff50eed546490170b7cb2..48b5a440674bf355ed543488ac94530355c7d06f 100644 (file)
@@ -46,6 +46,7 @@ GALLIUM_TARGET_CFLAGS = \
 
 GALLIUM_COMMON_LIB_DEPS = \
        -lm \
+       $(LIBUNWIND_LIBS) \
        $(LIBSENSORS_LIBS) \
        $(CLOCK_LIB) \
        $(PTHREAD_LIBS) \
index f941234de20ace635c1a43b7cbb2fd5da7e6296c..cf05f13ddd06c28f3f26f4cc8f50cfe57cf7d292 100644 (file)
 #include "u_debug_symbol.h"
 #include "u_debug_stack.h"
 
+#if defined(HAVE_LIBUNWIND)
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <dlfcn.h>
+
+void
+debug_backtrace_capture(struct debug_stack_frame *backtrace,
+                        unsigned start_frame,
+                        unsigned nr_frames)
+{
+   unw_cursor_t cursor;
+   unw_context_t context;
+   unw_proc_info_t pip;
+   unsigned i = 0;
+   int ret;
+
+   pip.unwind_info = NULL;
+
+   unw_getcontext(&context);
+   unw_init_local(&cursor, &context);
+
+   while ((start_frame > 0) && (unw_step(&cursor) > 0))
+      start_frame--;
+
+   while (unw_step(&cursor) > 0) {
+      char procname[256];
+      const char *filename;
+      unw_word_t off;
+      Dl_info dlinfo;
+
+      unw_get_proc_info(&cursor, &pip);
+
+      ret = unw_get_proc_name(&cursor, procname, 256, &off);
+      if (ret && ret != -UNW_ENOMEM) {
+         procname[0] = '?';
+         procname[1] = 0;
+      }
+
+       if (dladdr((void *)(uintptr_t)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
+               *dlinfo.dli_fname)
+           filename = dlinfo.dli_fname;
+       else
+           filename = "?";
+
+      snprintf(backtrace[i].buf, sizeof(backtrace[i].buf),
+            "%u: %s (%s%s+0x%x) [%p]", i, filename, procname,
+            ret == -UNW_ENOMEM ? "..." : "", (int)off,
+            (void *)(uintptr_t)(pip.start_ip + off));
+
+      i++;
+   }
+
+   while (i < nr_frames) {
+      backtrace[i].buf[0] = '\0';
+      i++;
+   }
+}
+
+void
+debug_backtrace_dump(const struct debug_stack_frame *backtrace,
+                     unsigned nr_frames)
+{
+   unsigned i;
+
+   for (i = 0; i < nr_frames; ++i) {
+      if (backtrace[i].buf[0] == '\0')
+         break;
+      debug_printf("\t%s\n", backtrace[i].buf);
+   }
+}
+
+void
+debug_backtrace_print(FILE *f,
+                      const struct debug_stack_frame *backtrace,
+                      unsigned nr_frames)
+{
+   unsigned i;
+
+   for (i = 0; i < nr_frames; ++i) {
+      if (backtrace[i].buf[0] == '\0')
+         break;
+      fprintf(f, "\t%s\n", backtrace[i].buf);
+   }
+}
+
+#else /* ! HAVE_LIBUNWIND */
+
 #if defined(PIPE_OS_WINDOWS)
 #include <windows.h>
 #endif
@@ -179,3 +268,5 @@ debug_backtrace_print(FILE *f,
          fprintf(f, "%s\n", symbol);
    }
 }
+
+#endif /* HAVE_LIBUNWIND */
index 04eba08f89a759e9bfd86c0e4435bbf10ded8557..0effcbe5259314f8ff38237e4cc14f015a070e4c 100644 (file)
 
 #include <stdio.h>
 
+#ifdef HAVE_LIBUNWIND
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#endif
+
 /**
  * @file
  * Stack backtracing.
@@ -46,15 +51,21 @@ extern "C" {
 /**
  * Represent a frame from a stack backtrace.
  *
- * XXX: Do not change this.
+#if defined(PIPE_OS_WINDOWS) && !defined(HAVE_LIBUNWIND)
+ * XXX: Do not change this. (passed to Windows' CaptureStackBackTrace())
+#endif
  *
  * TODO: This should be refactored as a void * typedef.
  */
 struct debug_stack_frame 
 {
+#ifdef HAVE_LIBUNWIND
+   char buf[128];
+#else
    const void *function;
+#endif
 };
-   
+
 
 void
 debug_backtrace_capture(struct debug_stack_frame *backtrace,