]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Add libunwind support for getting backtrace
authorAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 8 Mar 2019 11:38:56 +0000 (13:38 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 25 Mar 2019 12:16:16 +0000 (14:16 +0200)
This actually resolves symbols to readable names
making the backtrace useful.

configure.ac
m4/want_unwind.m4 [new file with mode: 0644]
src/lib/Makefile.am
src/lib/backtrace-string.c

index 75d832697bf7aefef3a15ef3732be6a9a0934b67..2092bb69599b7aed2cf22d9a71af796a5166f9ae 100644 (file)
@@ -91,6 +91,11 @@ AS_HELP_STRING([--with-ldap=yes|plugin], [Build with LDAP support]),
   TEST_WITH(ldap, $withval, plugin),
   want_ldap=no)
 
+AC_ARG_WITH(libunwind,
+AS_HELP_STRING([--with-libunwind], [Build with libunwind support (auto)]),
+  TEST_WITH(libunwind, $withval),
+  want_libunwind=auto)
+
 AC_ARG_WITH(vpopmail,
 AS_HELP_STRING([--with-vpopmail], [Build with vpopmail support (auto)]),
        if test x$withval = xno; then
@@ -520,6 +525,7 @@ DOVECOT_MNTCTL
 
 DOVECOT_SSL
 
+DOVECOT_WANT_UNWIND
 
 dnl **
 dnl ** userdb and passdb checks
diff --git a/m4/want_unwind.m4 b/m4/want_unwind.m4
new file mode 100644 (file)
index 0000000..4b7989e
--- /dev/null
@@ -0,0 +1,27 @@
+AC_DEFUN([DOVECOT_WANT_UNWIND], [
+  have_libunwind=no
+  AS_IF([test "$want_libunwind" != "no"], [
+    PKG_CHECK_EXISTS([libunwind], [
+      PKG_CHECK_MODULES([LIBUNWIND], [libunwind],[
+        dnl see if there is target-specific library
+        AC_CHECK_LIB([unwind-${build_cpu}], [_U${build_cpu}_init_local],[
+          have_libunwind=yes
+          LIBUNWIND_LIBS="$LIBUNWIND_LIBS -lunwind-${build_cpu}"
+          AC_DEFINE([HAVE_LIBUNWIND],,[Define this if you have libunwind])
+        ],[
+           have_libunwind=no
+           LIBUNWIND_LIBS=""
+           LIBUNWIND_CFLAGS=""
+        ])
+      ])
+     ])
+  ])
+
+  AC_MSG_CHECKING([whether we will be linking with libunwind]);
+  AS_IF([test "$want_libunwind" = yes], [
+     AS_IF([test "$have_libunwind" != yes], [
+       AC_MSG_ERROR([Cannot find libunwind])
+     ])
+  ])
+  AC_MSG_RESULT([$have_libunwind])
+])
index a4f6f54b2ea7f3243d468e9376d61b2d4c6312e9..67edf9aec5bb40733d37c4ec383227479fd8f848 100644 (file)
@@ -1,3 +1,6 @@
+AM_CPPFLAGS = \
+       $(LIBUNWIND_CFLAGS)
+
 noinst_LTLIBRARIES = liblib.la
 
 BUILT_SOURCES = $(srcdir)/unicodemap.c
@@ -10,6 +13,7 @@ $(srcdir)/UnicodeData.txt:
 $(srcdir)/unicodemap.c: $(srcdir)/unicodemap.pl $(srcdir)/UnicodeData.txt
        perl $(srcdir)/unicodemap.pl < $(srcdir)/UnicodeData.txt > $@
 
+liblib_la_LIBADD = $(LIBUNWIND_LIBS)
 liblib_la_SOURCES = \
        array.c \
        aqueue.c \
index 3effe18dbde1c6cbd45c1a14cbb25c22b7d02f38..7885116753e9f31c03c866f9a9b89305dff98a8a 100644 (file)
@@ -7,7 +7,56 @@
 #define MAX_STACK_SIZE 30
 #define STACK_SKIP_COUNT 2
 
-#if defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H)
+#if defined(HAVE_LIBUNWIND)
+
+#include <libunwind.h>
+
+int backtrace_append(string_t *str)
+{
+       char proc_name[256];
+       int ret;
+       unsigned int fp = 0;
+       unw_cursor_t c;
+       unw_context_t ctx;
+       unw_proc_info_t pip;
+
+       if ((ret = unw_getcontext(&ctx)) != 0) {
+               str_printfa(str, "unw_getcontext() failed: %d", ret);
+               return -1;
+       }
+       if ((ret = unw_init_local(&c, &ctx)) != 0) {
+               str_printfa(str, "unw_init_local() failed: %d", ret);
+               return -1;
+       }
+
+       do {
+               if (fp < STACK_SKIP_COUNT) {
+                       fp++;
+                       continue;
+               }
+               str_printfa(str, "#%d ", fp - STACK_SKIP_COUNT);
+               if ((ret = unw_get_proc_info(&c, &pip)) != 0) {
+                       str_printfa(str, "[unw_get_proc_info_failed(): %d]", ret);
+               } else if (pip.start_ip == 0 || pip.end_ip == 0) {
+                       str_append(str, "[no start/end information]");
+               } else if ((ret = unw_get_proc_name(&c, proc_name, sizeof(proc_name), 0)) != 0 &&
+                          ret != UNW_ENOMEM) {
+                       str_printfa(str, "[unw_get_proc_name() failed: %d]", ret);
+               } else {
+                       str_append_max(str, proc_name, sizeof(proc_name));
+                       str_printfa(str, "[0x%08lx]", pip.start_ip);
+               }
+               str_append(str, " -> ");
+               fp++;
+       } while ((ret = unw_step(&c)) > 0);
+
+       /* remove ' -> ' */
+       if (str->used > 4)
+               str_truncate(str, str->used - 4);
+       return ret == 0 ? 0 : -1;
+}
+
+#elif defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H)
 /* Linux */
 #include <execinfo.h>