#include "./stacktrace.hpp" #include #include #include #include namespace mijin { namespace { // // internal defines // // // internal constants // // // internal types // struct BacktraceData { std::optional error; std::vector stackframes; }; // // internal variables // // // internal functions // int backtraceFullCallback(void* data, std::uintptr_t programCounter, const char* filename, int lineno, const char* function) { BacktraceData& btData = *static_cast(data); btData.stackframes.push_back({ .address = reinterpret_cast(programCounter), .filename = filename ? filename : "", .function = function ? function : "", .lineNumber = lineno }); return 0; } void backtraceErrorCallback(void* data, const char* msg, int /* errnum */) { BacktraceData& btData = *static_cast(data); btData.error = msg; } thread_local backtrace_state* gBacktraceState = nullptr; } // namespace // // public functions // Result captureStacktrace(unsigned skipFrames) noexcept { BacktraceData btData; if (gBacktraceState == nullptr) { gBacktraceState = backtrace_create_state(/*filename = */ nullptr, /* threaded = */ false, &backtraceErrorCallback, &btData); } if (btData.error.has_value()) { return ResultError(std::move(*btData.error)); } if (gBacktraceState == nullptr) { return ResultError("Error initializing libbacktrace."); } backtrace_full(gBacktraceState, static_cast(skipFrames) + 1, &backtraceFullCallback, &backtraceErrorCallback, &btData); if (btData.error.has_value()) { return ResultError(std::move(*btData.error)); } return Stacktrace(std::move(btData.stackframes)); } } // namespace mijin