Basic implementation for universal exception tracing on linux/itanium

This commit is contained in:
Jeremy Rifkin 2024-08-15 19:59:03 -05:00
parent 2ae193256d
commit d3d697f439
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
4 changed files with 137 additions and 6 deletions

View File

@ -298,6 +298,7 @@ namespace cpptrace {
lazy_trace_holder& operator=(lazy_trace_holder&& other) noexcept;
~lazy_trace_holder();
// access
const raw_trace& get_raw_trace() const;
stacktrace& get_resolved_trace();
const stacktrace& get_resolved_trace() const;
private:

View File

@ -0,0 +1,51 @@
#include <cpptrace/cpptrace.hpp>
#include <iostream>
#include <sys/mman.h>
#include <array>
#include <cstring>
#ifdef _MSC_VER
#else
namespace cpptrace {
const raw_trace& raw_trace_from_current_exception();
const stacktrace& from_current_exception();
class unwind_interceptor {
public:
virtual ~unwind_interceptor();
};
}
/*
CPPTRACE_TRY {
foo();
} CPPTRACE_CATCH(std::runtime_error& e) {
fmt::println("Exception occurred: {}", e.get().what());
fmt::println("{}", cpptrace::from_current_exception());
}
try {
try {
foo();
} catch(const ::cpptrace::unwind_interceptor&) {}
} catch(std::runtime_error& e) {
fmt::println("Exception occurred: {}", e.get().what());
fmt::println("{}", cpptrace::from_current_exception());
}
*/
#define CPPTRACE_TRY \
try { \
try
#define CPPTRACE_CATCH(param) \
catch(cpptrace::unwind_interceptor&) { puts("shouldn't be here"); } \
} catch(param)
#endif

View File

@ -1,4 +1,5 @@
#include <cpptrace/cpptrace.hpp>
#include <cpptrace/from_current.hpp>
#include <atomic>
#include <cstddef>
@ -592,6 +593,14 @@ namespace cpptrace {
clear();
}
// access
const raw_trace& lazy_trace_holder::get_raw_trace() const {
if(resolved) {
throw std::logic_error(
"cpptrace::detail::lazy_trace_holder::get_resolved_trace called on resolved holder"
);
}
return trace;
}
stacktrace& lazy_trace_holder::get_resolved_trace() {
if(!resolved) {
raw_trace old_trace = std::move(trace);
@ -605,7 +614,7 @@ namespace cpptrace {
// TODO: Append to message somehow?
std::fprintf(
stderr,
"Exception occurred while resolving trace in cpptrace::exception object:\n%s\n",
"Exception occurred while resolving trace in cpptrace::detail::lazy_trace_holder:\n%s\n",
e.what()
);
}
@ -616,7 +625,7 @@ namespace cpptrace {
const stacktrace& lazy_trace_holder::get_resolved_trace() const {
if(!resolved) {
throw std::logic_error(
"cpptrace::detaillazy_trace_holder::get_resolved_trace called on unresolved const object"
"cpptrace::detail::lazy_trace_holder::get_resolved_trace called on unresolved const holder"
);
}
return resolved_trace;
@ -687,4 +696,62 @@ namespace cpptrace {
throw nested_exception(std::current_exception(), detail::get_raw_trace_and_absorb(skip + 1));
}
}
unwind_interceptor::~unwind_interceptor() = default;
namespace detail {
inline thread_local lazy_trace_holder current;
CPPTRACE_FORCE_NO_INLINE bool foobar(const std::type_info* this_ptr, const std::type_info* t, void**, unsigned) {
std::cout<<"--------UNGABUNGA!!-------- "<<this_ptr->name()<<" "<<t->name()<<std::endl;
current = lazy_trace_holder(cpptrace::generate_raw_trace(1));
return false;
}
std::array<void*, 11> new_vtable;
void clobber_type_info(const std::type_info& info) {
void* type_info_pointer = const_cast<void*>(reinterpret_cast<const void*>(&info));
void* type_info_vtable_pointer = *reinterpret_cast<void**>(type_info_pointer);
type_info_vtable_pointer = reinterpret_cast<void*>(reinterpret_cast<void**>(type_info_vtable_pointer) - 2); // adjust offset
memcpy(new_vtable.data(), type_info_vtable_pointer, 11 * sizeof(void*));
new_vtable[6] = reinterpret_cast<void*>(foobar);
if(
mprotect(
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(type_info_pointer) & ~(0xfffULL)),
4096,
PROT_WRITE | PROT_READ
) != 0
) {
perror("fuck");
throw std::runtime_error("mprotect failed");
}
*reinterpret_cast<void**>(type_info_pointer) = new_vtable.data() + 2;
if(
mprotect(
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(type_info_pointer) & ~(0xfffULL)),
4096,
PROT_READ
) != 0
) {
perror("fuck");
throw std::runtime_error("mprotect failed");
}
}
auto unwind_interceptor_type_info_clobberer = [](){
clobber_type_info(typeid(cpptrace::unwind_interceptor));
return 0;
}();
}
const raw_trace& raw_trace_from_current_exception() {
return detail::current.get_raw_trace();
}
const stacktrace& from_current_exception() {
return detail::current.get_resolved_trace();
}
}

View File

@ -1,4 +1,5 @@
#include <cpptrace/cpptrace.hpp>
#include <cpptrace/from_current.hpp>
#include <algorithm>
#include <cctype>
@ -6,9 +7,10 @@
#include <string>
void trace() {
cpptrace::generate_trace().print();
cpptrace::generate_trace().print_with_snippets();
throw cpptrace::logic_error("foobar");
// cpptrace::generate_trace().print();
// cpptrace::generate_trace().print_with_snippets();
// throw cpptrace::logic_error("foobar");
throw std::runtime_error("foobar");
}
void foo(int n) {
@ -35,5 +37,15 @@ void function_one(int) {
int main() {
cpptrace::absorb_trace_exceptions(false);
cpptrace::register_terminate_handler();
function_one(0);
CPPTRACE_TRY {
CPPTRACE_TRY {
function_one(0);
} CPPTRACE_CATCH(const std::logic_error& e) {
std::cout<<"Exception1: "<<e.what()<<std::endl;
std::cout<<cpptrace::from_current_exception().to_string(true)<<std::endl;
}
} CPPTRACE_CATCH(const std::exception& e) {
std::cout<<"Exception2: "<<e.what()<<std::endl;
std::cout<<cpptrace::from_current_exception().to_string(true)<<std::endl;
}
}