From: Martin Willi Date: Tue, 19 Nov 2013 17:40:51 +0000 (+0100) Subject: backtrace: Support backtraces on Windows without DbgHelp X-Git-Tag: 5.2.0dr6~24^2~125 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2127831cdaadd42755574e474c8017b752c0e032;p=thirdparty%2Fstrongswan.git backtrace: Support backtraces on Windows without DbgHelp While DbgHelp provides a convenient API to create backtraces, any executable linking against DbgHelp gets a more than a significant slow down. Further, it can only lookup global symbols, as it expects PDB files we can't produce with a MinGW build. With some core Kernel32.dll functionality, we can capture stack traces much faster. Together with the optional libbfd, we can print very fine backtraces. When --enable-bfd-backtraces is used on Windows, a libbfd.dll is required for the build. Such a DLL can be created from the binutils sources using: # build binutils with mingw... # extract archive members from binutils libraries x86_64-w64-mingw32-ar x $BINUTILS/bfd/.libs/libbfd.a x86_64-w64-mingw32-ar x $BINUTILS/intl/libintl.a x86_64-w64-mingw32-ar x $BINUTILS/libiberty/libiberty.a # create self-contained libbfd.a, with index x86_64-w64-mingw32-ar qs libbfd.a *.o # create DLL from static library x86_64-w64-mingw32-dlltool -e libbfd.o -l libbfd.lib libbfd.a x86_64-w64-mingw32-gcc -shared libbfd.a libbfd.o -o libbfd.dll --- diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c index f367fe233a..6101fb9c2f 100644 --- a/src/libstrongswan/utils/backtrace.c +++ b/src/libstrongswan/utils/backtrace.c @@ -30,6 +30,15 @@ #include +#ifdef WIN32 +# include +/* missing in MinGW */ +WINBOOL K32GetModuleInformation(HANDLE hProcess, HMODULE hModule, + LPMODULEINFO lpmodinfo, DWORD cb); +DWORD K32GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, + LPTSTR lpFilename, DWORD nSize); +#endif + typedef struct private_backtrace_t private_backtrace_t; /** @@ -80,9 +89,34 @@ static void println(FILE *file, char *format, ...) va_end(args); } -#ifdef HAVE_DLADDR +#ifdef HAVE_DBGHELP + +#include +#include + +/** + * Mutex to access non-thread-safe dbghelp functions + */ +static mutex_t *dbghelp_mutex; + +void backtrace_init() +{ + SymSetOptions(SYMOPT_LOAD_LINES); + SymInitialize(GetCurrentProcess(), NULL, TRUE); + dbghelp_mutex = mutex_create(MUTEX_TYPE_DEFAULT); +} +void backtrace_deinit() +{ + dbghelp_mutex->destroy(dbghelp_mutex); + SymCleanup(GetCurrentProcess()); +} + +#elif defined(HAVE_DLADDR) || defined(HAVE_BFD_H) + +#ifdef HAVE_DLADDR #include +#endif /** * Same as tty_escape_get(), but for a potentially NULL FILE* @@ -355,7 +389,6 @@ static void print_sourceline(FILE *file, char *filename, void *ptr, void* base) snprintf(buf, sizeof(buf), "addr2line -e %s %p", filename, ptr); #endif /* __APPLE__ */ - output = popen(buf, "r"); if (output) { @@ -378,29 +411,6 @@ static void print_sourceline(FILE *file, char *filename, void *ptr, void* base) #endif /* HAVE_BFD_H */ -#elif defined(HAVE_DBGHELP) /* && !HAVE_DLADDR */ - -#include -#include - -/** - * Mutex to access non-thread-safe dbghelp functions - */ -static mutex_t *dbghelp_mutex; - -void backtrace_init() -{ - SymSetOptions(SYMOPT_LOAD_LINES); - SymInitialize(GetCurrentProcess(), NULL, TRUE); - dbghelp_mutex = mutex_create(MUTEX_TYPE_DEFAULT); -} - -void backtrace_deinit() -{ - dbghelp_mutex->destroy(dbghelp_mutex); - SymCleanup(GetCurrentProcess()); -} - #else /* !HAVE_DLADDR && !HAVE_DBGHELP */ void backtrace_init() {} @@ -411,7 +421,7 @@ void backtrace_deinit() {} METHOD(backtrace_t, log_, void, private_backtrace_t *this, FILE *file, bool detailed) { -#if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(HAVE_DBGHELP) +#if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(WIN32) size_t i; char **strings = NULL; @@ -508,6 +518,26 @@ METHOD(backtrace_t, log_, void, } } else +#elif defined(WIN32) + HMODULE module; + MODULEINFO info; + char filename[MAX_PATH]; + + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + this->frames[i], &module) && + K32GetModuleInformation(GetCurrentProcess(), module, + &info, sizeof(info)) && + K32GetModuleFileNameExA(GetCurrentProcess(), module, + filename, sizeof(filename))) + { + println(file, " %s%s%s @ %p [%p]", + esc(file, TTY_FG_YELLOW), filename, + esc(file, TTY_FG_DEF), info.lpBaseOfDll, this->frames[i]); +#ifdef HAVE_BFD_H + print_sourceline(file, filename, this->frames[i], info.lpBaseOfDll); +#endif /* HAVE_BFD_H */ + } + else #endif /* HAVE_DLADDR/HAVE_DBGHELP */ { #ifdef HAVE_BACKTRACE @@ -709,7 +739,7 @@ static inline int backtrace_unwind(void **frames, int count) #ifdef HAVE_DBGHELP /** - * Windows variant for glibc backtrace() + * Windows dbghelp variant for glibc backtrace() */ static inline int backtrace_win(void **frames, int count) { @@ -763,6 +793,7 @@ static inline int backtrace_win(void **frames, int count) return got; } + #endif /* HAVE_DBGHELP */ /** @@ -795,6 +826,9 @@ backtrace_t *backtrace_create(int skip) frame_count = backtrace(frames, countof(frames)); #elif defined(HAVE_DBGHELP) frame_count = backtrace_win(frames, countof(frames)); +#elif defined(WIN32) + frame_count = CaptureStackBackTrace(skip, countof(frames), frames, NULL); + skip = 0; #endif frame_count = max(frame_count - skip, 0); this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));