From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#include "exception.h"
#include <cstring>
#include <memory>
#include <functional>
namespace panda {
using FrameProducers = std::vector<BacktraceProducer>;
RawTraceProducer get_default_raw_producer() noexcept;
BacktraceProducer get_default_bt_producer () noexcept;
static RawTraceProducer rawtrace_producer = get_default_raw_producer();
static FrameProducers frame_producers { get_default_bt_producer() };
BacktraceInfo::~BacktraceInfo() {};
Stackframe::~Stackframe() {};
string BacktraceInfo::to_string() const noexcept {
string r;
for(auto& frame: frames) {
// mimic gdb-style
r += "0x";
r += string::from_number(frame->address, 16);
if (frame->name) {
r += " in ";
r += frame->name;
}
if (frame->file) {
r += " at ";
r += frame->file;
if (frame->line_no) {
r += ":";
r += string::from_number(frame->line_no, 10);
}
} else if(frame->library) {
r += " from ";
r += frame->library;
}
r += "\n";
}
return r;
}
void Backtrace::install_producer(const BacktraceProducer &producer_) noexcept {
frame_producers.push_back(producer_);
}
void Backtrace::uninstall_producer(const BacktraceProducer& producer) noexcept {
for(auto it = frame_producers.begin(); it != frame_producers.end(); ++it) {
if (*it == producer) {
frame_producers.erase(it);
return;
}
}
assert(0 && "attempt to remove non-exiting backtrace producer");
}
Backtrace::Backtrace (const Backtrace& other) noexcept : buffer(other.buffer) {}
Backtrace::Backtrace () noexcept {
void* temp_buff[max_depth];
auto depth = rawtrace_producer(temp_buff, max_depth);
if (depth > 0) {
buffer.resize(depth);
std::memcpy(buffer.data(), temp_buff, sizeof(void*) * depth);
}
}
Backtrace::~Backtrace() {}
iptr<BacktraceInfo> Backtrace::get_backtrace_info() const noexcept {
StackFrames frames;
std::vector<BacktraceBackendSP> backends;
for(auto it = frame_producers.rbegin(); it != frame_producers.rend(); ++it) {
auto backend = (*it)(*this);
if (backend) backends.emplace_back(std::move(backend));
}
for (size_t i = 0; i < buffer.size(); ++i) {
bool done = false;
for (size_t j = 0; j < backends.size() && !done; ++j) {
done = backends[j]->produce_frame(frames, i);
}
}
return iptr<BacktraceInfo>(new BacktraceInfo(std::move(frames)));
}
string Backtrace::dump_trace() noexcept {
return Backtrace().get_backtrace_info()->to_string();
}
exception::exception () noexcept {}
exception::exception (const string& whats) noexcept : _whats(whats) {}
exception::exception (const exception& oth) noexcept : Backtrace(oth), _whats(oth._whats) {}
exception& exception::operator= (const exception& oth) noexcept {
_whats = oth._whats;
Backtrace::operator=(oth);
return *this;
}
const char* exception::what () const noexcept {
_whats = whats();
return _whats.c_str();
}
string exception::whats () const noexcept {
return _whats;
}
}