From f13a91d8a8059833daa11513b548941d9d2b6b35 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 26 Jan 2012 10:33:39 +0000 Subject: [PATCH] support backtraces on windows --- Jamfile | 15 +++++-- include/libtorrent/assert.hpp | 3 +- include/libtorrent/debug.hpp | 16 ++----- src/assert.cpp | 78 +++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 19 deletions(-) diff --git a/Jamfile b/Jamfile index d2d958f8f..518a31854 100755 --- a/Jamfile +++ b/Jamfile @@ -64,6 +64,14 @@ rule linking ( properties * ) } + if windows in $(properties) + && ( on in $(properties) + || debug in $(properties) + || on in $(properties) ) + { + result += dbghelp ; + } + # gcrypt libraries, if enabled if gcrypt in $(properties) || openssl in $(properties) { @@ -187,10 +195,8 @@ rule building ( properties * ) { local result ; - if ( linux in $(properties) - || darwin in $(properties) ) - && ( gcc in $(properties) - || darwin in $(properties) ) + if ( debug in $(properties) + || on in $(properties) ) { result += src/assert.cpp ; } @@ -345,6 +351,7 @@ lib advapi32 : : Advapi32 ; lib user32 : : User32 ; lib shell32 : : shell32 ; lib gdi32 : : gdi32 ; +lib dbghelp : : dbghelp ; # required for networking on beos lib netkit : : net /boot/system/lib shared ; diff --git a/include/libtorrent/assert.hpp b/include/libtorrent/assert.hpp index 8a66fe210..c4fffb855 100644 --- a/include/libtorrent/assert.hpp +++ b/include/libtorrent/assert.hpp @@ -46,9 +46,8 @@ extern char const* libtorrent_assert_log; #include -#ifdef __GNUC__ std::string demangle(char const* name); -#endif +void print_backtrace(char* out, int len); #if (defined __linux__ || defined __MACH__) && defined __GNUC__ && !TORRENT_USE_SYSTEM_ASSERT diff --git a/include/libtorrent/debug.hpp b/include/libtorrent/debug.hpp index 5acb343d6..7eec8f80b 100644 --- a/include/libtorrent/debug.hpp +++ b/include/libtorrent/debug.hpp @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/assert.hpp" #include "libtorrent/thread.hpp" -#include #include std::string demangle(char const* name); @@ -62,18 +61,9 @@ namespace libtorrent async_t& a = _async_ops[name]; if (a.stack.empty()) { - void* stack[50]; - int size = backtrace(stack, 50); - char** symbols = backtrace_symbols(stack, size); - - for (int i = 1; i < size; ++i) - { - char str[200]; - snprintf(str, sizeof(str), "%d: %s\n", i, demangle(symbols[i]).c_str()); - a.stack += str; - } - - free(symbols); + char stack_text[10000]; + print_backtrace(stack_text, sizeof(stack_text)); + a.stack = stack_text; } ++a.refs; } diff --git a/src/assert.cpp b/src/assert.cpp index 67a3060e9..85661b828 100644 --- a/src/assert.cpp +++ b/src/assert.cpp @@ -85,6 +85,21 @@ std::string demangle(char const* name) free(unmangled); return ret; } +#elif defined WIN32 + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 // XP + +#include "windows.h" +#include "dbghelp.h" + +std::string demangle(char const* name) +{ + char demangled_name[256]; + if (UnDecorateSymbolName(name, demangled_name, sizeof(demangled_name), UNDNAME_NO_THROW_SIGNATURES) == 0) + demangled_name[0] = 0; + return demangled_name; +} #else std::string demangle(char const* name) { return name; } @@ -114,6 +129,69 @@ void print_backtrace(char* out, int len) free(symbols); } + +#elif defined WIN32 + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 // XP + +#include "windows.h" +#include "libtorrent/utf8.hpp" + +#include "winbase.h" +#include "dbghelp.h" + +void print_backtrace(char* out, int len) +{ + typedef USHORT (*RtlCaptureStackBackTrace_t)( + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __out PVOID *BackTrace, + __out_opt PULONG BackTraceHash); + + static RtlCaptureStackBackTrace_t RtlCaptureStackBackTrace = 0; + + if (RtlCaptureStackBackTrace == 0) + { + // we don't actually have to free this library, everyone has it loaded + HMODULE lib = LoadLibrary(TEXT("kernel32.dll")); + RtlCaptureStackBackTrace = (RtlCaptureStackBackTrace_t)GetProcAddress(lib, "RtlCaptureStackBackTrace"); + if (RtlCaptureStackBackTrace == 0) + { + out[0] = 0; + return; + } + } + + int i; + void* stack[50]; + int size = CaptureStackBackTrace(0, 50, stack, 0); + + SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR), 1); + symbol->MaxNameLen = MAX_SYM_NAME; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + + HANDLE p = GetCurrentProcess(); + static bool sym_initialized = false; + if (!sym_initialized) + { + sym_initialized = true; + SymInitialize(p, NULL, true); + } + for (i = 0; i < size && len > 0; ++i) + { + int ret; + if (SymFromAddr(p, uintptr_t(stack[i]), 0, symbol)) + ret = snprintf(out, len, "%d: %s\n", i, symbol->Name); + else + ret = snprintf(out, len, "%d: \n", i); + + out += ret; + len -= ret; + } + free(symbol); +} + #else void print_backtrace(char* out, int len) {}