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
 |