Mesa (master): gallium/util: libunwind support

Rob Clark robclark at kemper.freedesktop.org
Mon Apr 3 15:48:13 UTC 2017


Module: Mesa
Branch: master
Commit: 70c272004f727457e852ba5f2498754b07a7d995
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=70c272004f727457e852ba5f2498754b07a7d995

Author: Rob Clark <robdclark at gmail.com>
Date:   Fri Mar 24 16:07:03 2017 -0400

gallium/util: libunwind support

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 at gmail.com>
Acked-by: Nicolai Hähnle <nicolai.haehnle at amd.com>

---

 configure.ac                               | 24 ++++++++
 src/gallium/Automake.inc                   |  1 +
 src/gallium/auxiliary/util/u_debug_stack.c | 91 ++++++++++++++++++++++++++++++
 src/gallium/auxiliary/util/u_debug_stack.h | 15 ++++-
 4 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 70885fb9a6..016e38fb59 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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],
diff --git a/src/gallium/Automake.inc b/src/gallium/Automake.inc
index a01fa54053..48b5a44067 100644
--- a/src/gallium/Automake.inc
+++ b/src/gallium/Automake.inc
@@ -46,6 +46,7 @@ GALLIUM_TARGET_CFLAGS = \
 
 GALLIUM_COMMON_LIB_DEPS = \
 	-lm \
+	$(LIBUNWIND_LIBS) \
 	$(LIBSENSORS_LIBS) \
 	$(CLOCK_LIB) \
 	$(PTHREAD_LIBS) \
diff --git a/src/gallium/auxiliary/util/u_debug_stack.c b/src/gallium/auxiliary/util/u_debug_stack.c
index f941234de2..cf05f13ddd 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.c
+++ b/src/gallium/auxiliary/util/u_debug_stack.c
@@ -36,6 +36,95 @@
 #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 */
diff --git a/src/gallium/auxiliary/util/u_debug_stack.h b/src/gallium/auxiliary/util/u_debug_stack.h
index 04eba08f89..0effcbe525 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.h
+++ b/src/gallium/auxiliary/util/u_debug_stack.h
@@ -30,6 +30,11 @@
 
 #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,




More information about the mesa-commit mailing list