89 lines
1.8 KiB
C++
89 lines
1.8 KiB
C++
|
|
#include "./stacktrace.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <backtrace.h>
|
|
|
|
namespace mijin
|
|
{
|
|
namespace
|
|
{
|
|
//
|
|
// internal defines
|
|
//
|
|
|
|
//
|
|
// internal constants
|
|
//
|
|
|
|
//
|
|
// internal types
|
|
//
|
|
|
|
struct BacktraceData
|
|
{
|
|
std::optional<std::string> error;
|
|
std::vector<Stackframe> 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<BacktraceData*>(data);
|
|
btData.stackframes.push_back({
|
|
.address = reinterpret_cast<void*>(programCounter),
|
|
.filename = filename ? filename : "<unknown>",
|
|
.function = function ? function : "<unknown>",
|
|
.lineNumber = lineno
|
|
});
|
|
return 0;
|
|
}
|
|
|
|
void backtraceErrorCallback(void* data, const char* msg, int /* errnum */)
|
|
{
|
|
BacktraceData& btData = *static_cast<BacktraceData*>(data);
|
|
btData.error = msg;
|
|
}
|
|
|
|
backtrace_state* gBacktraceState = nullptr;
|
|
} // namespace
|
|
|
|
//
|
|
// public functions
|
|
//
|
|
|
|
Result<Stacktrace> 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<int>(skipFrames) + 1, &backtraceFullCallback, &backtraceErrorCallback, &btData);
|
|
if (btData.error.has_value())
|
|
{
|
|
return ResultError(std::move(*btData.error));
|
|
}
|
|
|
|
return Stacktrace(std::move(btData.stackframes));
|
|
}
|
|
|
|
} // namespace mijin
|