Skip to content

Commit

Permalink
Win32: add experimental stack backtraces with symbol lookup
Browse files Browse the repository at this point in the history
(cherry picked from commit f4685e7)
  • Loading branch information
qris committed Jul 23, 2017
1 parent 1b97080 commit 4127ec1
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 37 deletions.
2 changes: 1 addition & 1 deletion infrastructure/cmake/CMakeLists.txt
Expand Up @@ -378,7 +378,7 @@ file(REMOVE "${boxconfig_h_file}")
file(WRITE "${boxconfig_h_file}" "// Auto-generated by CMake. Do not edit.\n")

if(WIN32)
target_link_libraries(lib_common PUBLIC ws2_32 gdi32)
target_link_libraries(lib_common PUBLIC dbghelp ws2_32 gdi32)
endif()

# On Windows we want to statically link zlib to make debugging and distribution easier,
Expand Down
2 changes: 1 addition & 1 deletion lib/common/Box.h
Expand Up @@ -25,7 +25,7 @@

// Show backtraces on exceptions in release builds until further notice
// (they are only logged at TRACE level anyway)
#ifdef HAVE_EXECINFO_H
#if defined WIN32 || defined HAVE_EXECINFO_H
#define SHOW_BACKTRACE_ON_EXCEPTION
#endif

Expand Down
10 changes: 9 additions & 1 deletion lib/common/MainHelper.cpp
Expand Up @@ -11,13 +11,14 @@

#ifdef WIN32
# include <winsock2.h>
# include <dbghelp.h>
#endif

#include "autogen_CommonException.h"
#include "Logging.h"

// Windows requires winsock to be initialised before use, unlike every other platform.
void mainhelper_init_win32_sockets()
void mainhelper_init_win32()
{
#ifdef WIN32
WSADATA info;
Expand All @@ -32,6 +33,13 @@ void mainhelper_init_win32_sockets()
THROW_WIN_ERROR_NUMBER("Failed to initialise Windows Sockets library", wserrno,
CommonException, Internal)
}

HANDLE hProcess = GetCurrentProcess();
if(!SymInitialize(hProcess, NULL, TRUE))
{
BOX_LOG_WIN_WARNING("Failed to initialize symbol lookup for exception "
"backtraces");
}
#endif
}

5 changes: 2 additions & 3 deletions lib/common/MainHelper.h
Expand Up @@ -19,14 +19,14 @@
#include "BoxException.h"
#include "Logging.h"

void mainhelper_init_win32_sockets();
void mainhelper_init_win32();

#define MAINHELPER_START \
if(argc == 2 && ::strcmp(argv[1], "--version") == 0) \
{ printf(BOX_VERSION "\n"); return 0; } \
MEMLEAKFINDER_INIT \
MEMLEAKFINDER_START \
mainhelper_init_win32_sockets(); \
mainhelper_init_win32(); \
try {

#define MAINHELPER_END \
Expand All @@ -48,6 +48,5 @@ void mainhelper_init_win32_sockets();
#define MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT(file, marker)
#endif // BOX_MEMORY_LEAK_TESTING


#endif // MAINHELPER__H

120 changes: 89 additions & 31 deletions lib/common/Utils.cpp
Expand Up @@ -28,6 +28,18 @@
#include <dlfcn.h>
#endif

#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif

#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif

#ifdef WIN32
# include <dbghelp.h>
#endif

#ifdef NEED_BOX_VERSION_H
# include "BoxVersion.h"
#endif
Expand Down Expand Up @@ -134,9 +146,19 @@ std::string RemoveSuffix(const std::string& suffix, const std::string& haystack)
static std::string demangle(const std::string& mangled_name)
{
std::string demangled_name = mangled_name;

#ifdef HAVE_CXXABI_H
char buffer[1024];

#if defined WIN32
if(UnDecorateSymbolName(mangled_name.c_str(), buffer, sizeof(buffer),
UNDNAME_COMPLETE))
{
demangled_name = buffer;
}
else
{
BOX_LOG_WIN_ERROR("UnDecorateSymbolName failed");
}
#elif defined HAVE_CXXABI_H
int status;
size_t length = sizeof(buffer);

Expand Down Expand Up @@ -174,53 +196,89 @@ static std::string demangle(const std::string& mangled_name)
"with unknown error " << status <<
": " << mangled_name);
}
#endif // HAVE_CXXABI_H
#endif // HAVE_CXXABI_H

return demangled_name;
}

void DumpStackBacktrace()
{
#ifdef HAVE_EXECINFO_H
void *array[20];
const int max_length = 20;
void *array[max_length];

#if defined WIN32
size_t size = CaptureStackBackTrace(0, max_length, array, NULL);
#elif defined HAVE_EXECINFO_H
size_t size = backtrace(array, 20);
BOX_TRACE("Obtained " << size << " stack frames.");
#else
BOX_TRACE("Backtrace support was not compiled in");
return;
#endif

BOX_TRACE("Obtained " << size << " stack frames.");
DumpStackBacktrace(size, array);
}

void DumpStackBacktrace(size_t size, void * const * array)
{
#if defined WIN32
HANDLE hProcess = GetCurrentProcess();
// SymInitialize was called in mainhelper_init_win32()
DWORD64 displacement;
char symbol_info_buf[sizeof(SYMBOL_INFO) + 256];
PSYMBOL_INFO pInfo = (SYMBOL_INFO *)symbol_info_buf;
pInfo->MaxNameLen = 256;
pInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
#endif

for(size_t i = 0; i < size; i++)
{
std::ostringstream output;
output << "Stack frame " << i << ": ";

#ifdef HAVE_DLADDR
Dl_info info;
int result = dladdr(array[i], &info);
#if defined WIN32
if(!SymFromAddr(hProcess, (DWORD64)array[i], &displacement, pInfo))
#elif defined HAVE_DLADDR
Dl_info info;
int result = dladdr(array[i], &info);
if(result == 0)
#endif
{
BOX_LOG_NATIVE_WARNING("Failed to resolve "
"backtrace address " << array[i]);
output << "unresolved address " << array[i];
continue;
}

if(result == 0)
{
BOX_LOG_SYS_WARNING("Failed to resolve "
"backtrace address " << array[i]);
output << "unresolved address " << array[i];
}
else if(info.dli_sname == NULL)
{
output << "unknown address " << array[i];
}
else
{
uint64_t diff = (uint64_t) array[i];
diff -= (uint64_t) info.dli_saddr;
output << demangle(info.dli_sname) << "+" <<
(void *)diff;
}
#else
output << "address " << array[i];
#endif // HAVE_DLADDR
const char* mangled_name = NULL;
void* start_addr;
#if defined WIN32
mangled_name = &(pInfo->Name[0]);
start_addr = (void *)(pInfo->Address);
#elif defined HAVE_DLADDR
mangled_name = info.dli_sname;
start_addr = info.dli_saddr;
#else
output << "address " << array[i];
BOX_TRACE(output.str());
continue;
#endif

if(mangled_name == NULL)
{
output << "unknown address " << array[i];
}
else
{
uint64_t diff = (uint64_t) array[i];
diff -= (uint64_t) start_addr;
output << demangle(mangled_name) << "+" <<
(void *)diff;
}

BOX_TRACE(output.str());
}
#else // !HAVE_EXECINFO_H
BOX_TRACE("Backtrace support was not compiled in");
#endif // HAVE_EXECINFO_H
}


Expand Down

0 comments on commit 4127ec1

Please sign in to comment.