Alien-libpanda
view release on metacpan or search on metacpan
Makefile.PL view on Meta::CPAN
SRC => ['src'],
INC => '-Isrc',
BIN_SHARE => { INCLUDE => {'src' => '/'} },
CCFLAGS => '-Wall -Wextra',
MIN_PERL_VERSION => '5.12.0',
test => { SRC => 't', BIN_DEPS => 'Test::Catch' },
LIBS => ['-lexecinfo', ''],
);
if ($ENV{SANITIZE}) {
($params{CCFLAGS}||='') .= ' -fsanitize=undefined -fsanitize=address -fno-omit-frame-pointer';
$params{LIBS}[1] .= ' -lubsan -lasan'; #sanitizer
$params{LIBS}[0] .= ' -lubsan -lasan'; #sanitizer
}
write_makefile(%params);
src/panda/exception.h view on Meta::CPAN
#pragma once
#include <exception>
#include <vector>
#include "string.h"
#include "refcnt.h"
namespace panda {
struct Stackframe: public Refcnt {
string file;
string library;
string name;
string mangled_name;
std::uint64_t address = 0;
std::uint64_t offset = 0;
std::uint64_t line_no = 0;
};
using StackframePtr = iptr<Stackframe>;
struct BacktraceInfo : Refcnt {
virtual ~BacktraceInfo();
virtual const std::vector<StackframePtr>& get_frames() const = 0;
virtual string to_string() const = 0;
};
using RawTrace = std::vector<void*>;
using BacktraceProducer = iptr<BacktraceInfo>(*)(const RawTrace&);
struct Backtrace {
static const constexpr int max_depth = 50;
Backtrace () noexcept;
t/exception.cc view on Meta::CPAN
static BacktraceProducer glib_producer(glib_produce);
static bool _init() {
Backtrace::install_producer(glib_producer);
return true;
}
static bool init = _init();
static std::regex re("(.+)\\((.+)\\+0x(.+)\\) \\[0x(.+)\\]");
static StackframePtr as_frame (const char* symbol) {
using guard_t = std::unique_ptr<char*, std::function<void(char**)>>;
auto r = StackframePtr(new Stackframe());
std::cmatch what;
if (regex_match(symbol, what, re)) {
panda::string dll (what[1].first, what[1].length());
panda::string mangled_name (what[2].first, what[2].length());
panda::string symbol_offset (what[3].first, what[3].length());
panda::string address (what[4].first, what[4].length());
int status;
char* demangled_name = abi::__cxa_demangle(mangled_name.c_str(), nullptr, nullptr, &status);
guard_t guard;
t/exception.cc view on Meta::CPAN
auto offset_r = from_chars(symbol_offset.data(), symbol_offset.data() + symbol_offset.size(), offset, 16);
if (!offset_r.ec) { r->offset = offset; }
else { r->offset = 0; }
//printf("symbol = %s\n", symbol);
}
return r;
}
struct glib_backtrace: BacktraceInfo {
glib_backtrace(std::vector<StackframePtr>&& frames_):frames{std::move(frames_)}{}
const std::vector<StackframePtr>& get_frames() const override { return frames; }
virtual string to_string() const override { std::abort(); }
std::vector<StackframePtr> frames;
};
iptr<BacktraceInfo> glib_produce(const RawTrace& buffer) {
using guard_t = std::unique_ptr<char**, std::function<void(char***)>>;
char** symbols = backtrace_symbols(buffer.data(), buffer.size());
if (symbols) {
guard_t guard(&symbols, [](char*** ptr) { free(*ptr); });
std::vector<StackframePtr> frames;
frames.reserve(buffer.size());
for (int i = 0; i < static_cast<int>(buffer.size()); ++i) {
// printf("symbol = %s\n", symbols[i]);
auto frame = as_frame(symbols[i]);
frames.emplace_back(std::move(frame));
}
auto ptr = new glib_backtrace(std::move(frames));
return iptr<BacktraceInfo>(ptr);
}
return iptr<BacktraceInfo>();
}
// prevent inlining
extern "C" {
int v = 0;
t/exception.cc view on Meta::CPAN
TEST_CASE("exception with trace, catch exact exception", "[exception]") {
bool was_catch = false;
try {
fn48();
} catch( const bt<std::invalid_argument>& e) {
auto trace = e.get_backtrace_info();
REQUIRE(e.get_trace().size() == 50);
REQUIRE((bool)trace);
REQUIRE(e.what() == std::string("Oops!"));
auto frames = trace->get_frames();
REQUIRE(frames.size() >= 47);
StackframePtr fn00_frame = nullptr;
StackframePtr fn46_frame = nullptr;
for(auto& f : frames) {
std::cout << f->name << "\n";
if (f->name.find("fn00") != string::npos) { fn00_frame = f; }
if (f->name.find("fn46") != string::npos) { fn46_frame = f; }
}
REQUIRE(fn00_frame);
REQUIRE(fn46_frame);
CHECK_THAT( fn00_frame->library, Catch::Matchers::Contains( "MyTest.so" ) );
CHECK_THAT( fn00_frame->name, Catch::Matchers::Contains( "fn00" ) );
CHECK( fn46_frame->address > 0);
CHECK( fn46_frame->offset > 0);
CHECK_THAT( fn46_frame->library, Catch::Matchers::Contains( "MyTest.so" ) );
was_catch = true;
}
REQUIRE(was_catch);
}
TEST_CASE("exception with trace, catch non-final class", "[exception]") {
bool was_catch = false;
try {
fn48();
} catch( const std::logic_error& e) {
REQUIRE(e.what() == std::string("Oops!"));
auto bt = dyn_cast<const panda::Backtrace*>(&e);
REQUIRE(bt);
REQUIRE(bt->get_trace().size() == 50);
auto trace = bt->get_backtrace_info();
REQUIRE((bool)trace);
auto frames = trace->get_frames();
REQUIRE(frames.size() >= 47);
StackframePtr fn00_frame = nullptr;
StackframePtr fn46_frame = nullptr;
for(auto& f : frames) {
if (f->name.find("fn00") != string::npos) { fn00_frame = f; }
if (f->name.find("fn46") != string::npos) { fn46_frame = f; }
}
CHECK(fn00_frame);
CHECK(fn46_frame);
was_catch = true;
}
REQUIRE(was_catch);
}
TEST_CASE("panda::exception with string", "[exception]") {
bool was_catch = false;
try {
throw panda::exception("my-description");
} catch( const exception& e) {
( run in 0.954 second using v1.01-cache-2.11-cpan-df04353d9ac )