backtrace: add an alternative stack unwinding implementation using libunwind
authorMartin Willi <martin@revosec.ch>
Fri, 5 Apr 2013 14:26:27 +0000 (16:26 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 6 May 2013 13:15:24 +0000 (15:15 +0200)
configure.in
src/libstrongswan/Makefile.am
src/libstrongswan/utils/backtrace.c

index f0a2ec9..311b15c 100644 (file)
@@ -238,6 +238,7 @@ ARG_ENABL_SET([radattr],        [enable plugin to inject and process custom RADI
 ARG_ENABL_SET([vstr],           [enforce using the Vstr string library to replace glibc-like printf hooks.])
 ARG_ENABL_SET([monolithic],     [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.])
 ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
+ARG_ENABL_SET([unwind-backtraces],[use libunwind to create backtraces for memory leaks and segfaults.])
 ARG_ENABL_SET([unit-tests],     [enable unit tests using the check test framework.])
 ARG_ENABL_SET([tkm],            [enable Trusted Key Manager support.])
 
@@ -886,6 +887,14 @@ if test x$bfd_backtraces = xtrue; then
        AC_SUBST(BFDLIB)
 fi
 
+if test x$unwind_backtraces = xtrue; then
+       AC_CHECK_LIB([unwind],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([libunwind not found!])],[])
+       AC_CHECK_HEADER([libunwind.h],[AC_DEFINE([HAVE_LIBUNWIND_H],,[have libunwind.h])],
+               [AC_MSG_ERROR([libunwind.h header not found!])])
+       UNWINDLIB="-lunwind"
+       AC_SUBST(UNWINDLIB)
+fi
+
 AM_CONDITIONAL(USE_DEV_HEADERS, [test "x$dev_headers" != xno])
 if test x$dev_headers = xyes; then
        dev_headers="$includedir/strongswan"
index 81e271a..ce6df28 100644 (file)
@@ -79,7 +79,7 @@ endif
 
 library.lo :   $(top_builddir)/config.status
 
-libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) $(BFDLIB)
+libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) $(BFDLIB) $(UNWINDLIB)
 
 INCLUDES = -I$(top_srcdir)/src/libstrongswan
 AM_CFLAGS = \
index 77137f9..dd2be7a 100644 (file)
@@ -373,7 +373,7 @@ void backtrace_deinit() {}
 METHOD(backtrace_t, log_, void,
        private_backtrace_t *this, FILE *file, bool detailed)
 {
-#ifdef HAVE_BACKTRACE
+#if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H)
        size_t i;
        char **strings;
 
@@ -420,9 +420,9 @@ METHOD(backtrace_t, log_, void,
                }
        }
        free (strings);
-#else /* !HAVE_BACKTRACE */
-       println(file, "C library does not support backtrace().");
-#endif /* HAVE_BACKTRACE */
+#else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
+       println(file, "no support for backtrace()/libunwind");
+#endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
 }
 
 METHOD(backtrace_t, contains_function, bool,
@@ -518,6 +518,33 @@ METHOD(backtrace_t, destroy, void,
        free(this);
 }
 
+#ifdef HAVE_LIBUNWIND_H
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+/**
+ * libunwind variant for glibc backtrace()
+ */
+static inline int backtrace_unwind(void **frames, int count)
+{
+       unw_context_t context;
+       unw_cursor_t cursor;
+       unw_word_t ip;
+       int depth = 0;
+
+       unw_getcontext(&context);
+       unw_init_local(&cursor, &context);
+       do
+       {
+               unw_get_reg(&cursor, UNW_REG_IP, &ip);
+               frames[depth++] = (void*)ip;
+       }
+       while (depth < count && unw_step(&cursor) > 0);
+
+       return depth;
+}
+#endif /* HAVE_UNWIND */
+
 /**
  * See header
  */
@@ -527,7 +554,9 @@ backtrace_t *backtrace_create(int skip)
        void *frames[50];
        int frame_count = 0;
 
-#ifdef HAVE_BACKTRACE
+#ifdef HAVE_LIBUNWIND_H
+       frame_count = backtrace_unwind(frames, countof(frames));
+#elif defined(HAVE_BACKTRACE)
        frame_count = backtrace(frames, countof(frames));
 #endif /* HAVE_BACKTRACE */
        frame_count = max(frame_count - skip, 0);