// adopted from https://github.com/boostorg/stacktrace/tree/develop/include/boost/stacktrace/detail
#include "../exception.h"
#include "exception_debug.h"
#include <windows.h>
#include <dbgeng.h>
#ifdef _MSC_VER
static panda::string demangle(const panda::string& mangled) {
return mangled; //TODO: msvc demangler
}
#else
#include <cxxabi.h>
static panda::string demangle(const panda::string& mangled) {
panda::string result;
int status;
char* d = abi::__cxa_demangle(mangled.c_str(), nullptr, nullptr, &status);
if (d) {
result = d;
free(d);
}
return result;
}
#endif
namespace panda {
class SimpleDebuggingSymbols: public debugging_symbols {
using debugging_symbols::debugging_symbols;
public:
void gather(const void* addr, Stackframe& f) const noexcept {
if (!is_inited()) { return; }
const ULONG64 offset = reinterpret_cast<ULONG64>(addr);
// get name and dll
string fqn;
char buff[256] = {0};
buff[0] = '\0';
ULONG size = 0;
bool res = (S_OK == idebug_->GetNameByOffset(offset, buff, sizeof(buff), &size, 0 ));
if (!res && size != 0) {
fqn.resize(size);
res = (S_OK == idebug_->GetNameByOffset(offset, fqn.buf(), size, &size, 0));
if (res) { fqn.length(size - 1); }
} else if (res) {
fqn.assign(buff, size - 1);
}
if (res) {
//std::cout << "fqn: " << buff << "\n";
auto delimiter = fqn.find_first_of('!');
if (delimiter == string::npos) { f.library = fqn; } // can't get name
else {
auto dll = fqn.substr(0, delimiter);
auto mangled = fqn.substr(delimiter + 1);
auto demangled = mangled;
if (mangled.size() > 2 && (mangled[0] == '_') && (mangled[1] == 'Z')) {
demangled = demangle(mangled);
}
f.mangled_name = mangled;
f.name = demangled;
f.library = dll;
}
}
// get source file & line_no ; actually does not work on mingw
buff[0] = '\0';
ULONG line_no = 0;
string file;
res = (S_OK == idebug_->GetLineByOffset(reinterpret_cast<ULONG64>(addr), &line_no, buff, sizeof(buff), &size, 0));
//std::cout << "l =" << line_no << "\n";
if (!res && size != 0) {
file.resize(size);
res = (S_OK == idebug_->GetLineByOffset(reinterpret_cast<ULONG64>(addr), &line_no, file.buf(), size, &size, 0));
} else if (res) {
file = buff;
}
if (res) {
file.length(size - 1);
f.line_no = line_no;
f.file = file;
}
f.address = reinterpret_cast<uint64_t>(addr);
}
};
RawTraceProducer get_default_raw_producer () noexcept {
return [](void** ptr, int sz) -> int {
auto r = ::CaptureStackBackTrace(1, static_cast<unsigned long>(sz), ptr, nullptr);
return r;
};
}
struct WinBacktrace: BacktraceBackend {
const Backtrace& raw_traces;
SimpleDebuggingSymbols idebug;
WinBacktrace(const Backtrace& raw_traces_) noexcept: raw_traces{raw_traces_} {}
bool produce_frame(StackFrames& frames, size_t i) override {
StackframeSP frame;
if (!idebug.is_inited()) return false;
auto raw_frame = raw_traces.buffer.at(i);
frame = StackframeSP(new Stackframe());
idebug.gather(raw_frame, *frame);
frames.emplace_back(std::move(frame));
return true;
}
};
BacktraceProducer get_default_bt_producer () noexcept {
return [](const Backtrace& raw_traces) -> BacktraceBackendSP {
return new WinBacktrace(raw_traces);
};
}
}