Make backtrace work on windows
This commit is contained in:
parent
2299867320
commit
efbe606961
@ -37,7 +37,8 @@ set(SOURCES
|
||||
data/DataFixture.cpp
|
||||
data/DataUtils.cpp
|
||||
data/Data.cpp
|
||||
assert/backtrace.cpp
|
||||
assert/backtrace_nonwindows.cpp
|
||||
assert/backtrace_windows.cpp
|
||||
assert/AssertFailed.cpp
|
||||
system/get_total_memory.cpp
|
||||
system/homedir.cpp
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
namespace cpputils {
|
||||
std::string backtrace();
|
||||
|
||||
//TODO Refactor (for example: RAII or at least try{}finally{} instead of free())
|
||||
//TODO Use the following? https://github.com/bombela/backward-cpp
|
||||
void showBacktraceOnSigSegv();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
#include "backtrace.h"
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
@ -12,12 +14,9 @@ using std::string;
|
||||
using std::ostringstream;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
//TODO Use the following? https://github.com/bombela/backward-cpp
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
//TODO Refactor (for example: RAII or at least try{}finally{} instead of free())
|
||||
|
||||
namespace {
|
||||
std::string demangle(const string &mangledName) {
|
||||
string result;
|
||||
int status = -10;
|
||||
@ -37,7 +36,8 @@ namespace cpputils {
|
||||
if (startMangledName == string::npos || endMangledName == string::npos) {
|
||||
return backtraceLine;
|
||||
}
|
||||
return demangle(backtraceLine.substr(startMangledName+1, endMangledName-startMangledName-1)) + ": (" + backtraceLine.substr(0, startMangledName) + backtraceLine.substr(endMangledName);
|
||||
return demangle(backtraceLine.substr(startMangledName + 1, endMangledName - startMangledName - 1)) + ": (" +
|
||||
backtraceLine.substr(0, startMangledName) + backtraceLine.substr(endMangledName);
|
||||
}
|
||||
|
||||
string backtrace_to_string(void *array[], size_t size) {
|
||||
@ -49,20 +49,29 @@ namespace cpputils {
|
||||
free(ptr);
|
||||
return result.str();
|
||||
}
|
||||
}
|
||||
|
||||
string backtrace() {
|
||||
constexpr unsigned int MAX_SIZE = 100;
|
||||
void *array[MAX_SIZE];
|
||||
size_t size = ::backtrace(array, MAX_SIZE);
|
||||
return backtrace_to_string(array, size);
|
||||
}
|
||||
string backtrace() {
|
||||
constexpr unsigned int MAX_SIZE = 100;
|
||||
void *array[MAX_SIZE];
|
||||
size_t size = ::backtrace(array, MAX_SIZE);
|
||||
return backtrace_to_string(array, size);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void sigsegv_handler(int) {
|
||||
LOG(ERROR, "SIGSEGV\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void showBacktraceOnSigSegv() {
|
||||
signal(SIGSEGV, sigsegv_handler);
|
||||
}
|
||||
}
|
||||
|
||||
void showBacktraceOnSigSegv() {
|
||||
auto result = signal(SIGSEGV, sigsegv_handler);
|
||||
if (SIG_ERR == result) {
|
||||
LOG(ERROR, "Failed to set sigsegv signal handler. Errno: {}", errno);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
127
src/cpp-utils/assert/backtrace_windows.cpp
Normal file
127
src/cpp-utils/assert/backtrace_windows.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include "backtrace.h"
|
||||
#include <signal.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "../logging/logging.h"
|
||||
#include <Windows.h>
|
||||
#include <Dbghelp.h>
|
||||
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
namespace {
|
||||
std::string backtrace_to_string(CONTEXT* context_record) {
|
||||
std::ostringstream backtrace;
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
if (!::SymInitialize(process, NULL, TRUE)) {
|
||||
DWORD error = GetLastError();
|
||||
backtrace << "[Can't get backtrace. SymInitialize failed with error code " << std::dec << error << "]\n";
|
||||
}
|
||||
else {
|
||||
// Initialize stack walking.
|
||||
STACKFRAME64 stack_frame;
|
||||
memset(&stack_frame, 0, sizeof(stack_frame));
|
||||
#if defined(_WIN64)
|
||||
int machine_type = IMAGE_FILE_MACHINE_AMD64;
|
||||
stack_frame.AddrPC.Offset = context_record->Rip;
|
||||
stack_frame.AddrFrame.Offset = context_record->Rbp;
|
||||
stack_frame.AddrStack.Offset = context_record->Rsp;
|
||||
#else
|
||||
int machine_type = IMAGE_FILE_MACHINE_I386;
|
||||
stack_frame.AddrPC.Offset = context_record->Eip;
|
||||
stack_frame.AddrFrame.Offset = context_record->Ebp;
|
||||
stack_frame.AddrStack.Offset = context_record->Esp;
|
||||
#endif
|
||||
stack_frame.AddrPC.Mode = AddrModeFlat;
|
||||
stack_frame.AddrFrame.Mode = AddrModeFlat;
|
||||
stack_frame.AddrStack.Mode = AddrModeFlat;
|
||||
|
||||
auto symbol_storage = std::make_unique<char[]>(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR));
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbol_storage.get();
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (StackWalk64(machine_type,
|
||||
GetCurrentProcess(),
|
||||
GetCurrentThread(),
|
||||
&stack_frame,
|
||||
context_record,
|
||||
nullptr,
|
||||
&SymFunctionTableAccess64,
|
||||
&SymGetModuleBase64,
|
||||
nullptr)) {
|
||||
|
||||
backtrace << "#" << (i++) << " ";
|
||||
|
||||
DWORD64 displacement = 0;
|
||||
|
||||
if (SymFromAddr(process, (DWORD64)stack_frame.AddrPC.Offset, &displacement, symbol))
|
||||
{
|
||||
IMAGEHLP_MODULE64 moduleInfo;
|
||||
std::memset(&moduleInfo, 0, sizeof(IMAGEHLP_MODULE64));
|
||||
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
|
||||
|
||||
if (::SymGetModuleInfo64(process, symbol->ModBase, &moduleInfo)) {
|
||||
backtrace << moduleInfo.ModuleName << ":";
|
||||
}
|
||||
backtrace << "0x" << std::hex << (DWORD64)stack_frame.AddrPC.Offset << ": ";
|
||||
|
||||
backtrace << symbol->Name << " + 0x" << std::hex << static_cast<int64_t>(displacement);
|
||||
}
|
||||
else {
|
||||
DWORD error = GetLastError();
|
||||
backtrace << std::hex << (DWORD64)stack_frame.AddrPC.Offset << ": [can't get symbol. SymFromAddr failed with error code " << std::dec << error << "]";
|
||||
}
|
||||
|
||||
DWORD dwDisplacement;
|
||||
IMAGEHLP_LINE64 line;
|
||||
SymSetOptions(SYMOPT_LOAD_LINES);
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (::SymGetLineFromAddr64(process, (DWORD64)stack_frame.AddrPC.Offset, &dwDisplacement, &line)) {
|
||||
backtrace << " at " << line.FileName << ":" << std::dec << line.LineNumber;
|
||||
}
|
||||
else {
|
||||
DWORD error = GetLastError();
|
||||
backtrace << " at [file/line unavailable, SymGetLineFromAddr64 failed with error code " << std::dec << error << "]";
|
||||
}
|
||||
backtrace << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return backtrace.str();
|
||||
}
|
||||
|
||||
|
||||
LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
|
||||
{
|
||||
std::string backtrace = backtrace_to_string(pExceptionInfo->ContextRecord);
|
||||
LOG(ERROR, "Top level exception. Backtrace:\n{}", backtrace);
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
std::string backtrace() {
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(CONTEXT));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
RtlCaptureContext(&context);
|
||||
return backtrace_to_string(&context);
|
||||
}
|
||||
|
||||
void showBacktraceOnSigSegv() {
|
||||
SetUnhandledExceptionFilter(TopLevelExceptionHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user