From 83714577a9c99c9971ce2d3968ab773b37f4ea5b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 5 Apr 2013 16:26:27 +0200 Subject: [PATCH] backtrace: add an alternative stack unwinding implementation using libunwind --- configure.in | 9 +++++++ src/libstrongswan/Makefile.am | 2 +- src/libstrongswan/utils/backtrace.c | 39 +++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/configure.in b/configure.in index f0a2ec961..311b15c6b 100644 --- a/configure.in +++ b/configure.in @@ -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" diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 81e271a8a..ce6df2855 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -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 = \ diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c index 77137f9f1..dd2be7a0a 100644 --- a/src/libstrongswan/utils/backtrace.c +++ b/src/libstrongswan/utils/backtrace.c @@ -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 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);