From d3d697f439860a81b150f314acfcd15da93353cb Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:59:03 -0500 Subject: [PATCH] Basic implementation for universal exception tracing on linux/itanium --- include/cpptrace/cpptrace.hpp | 1 + include/cpptrace/from_current.hpp | 51 ++++++++++++++++++++++ src/cpptrace.cpp | 71 ++++++++++++++++++++++++++++++- test/demo.cpp | 20 +++++++-- 4 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 include/cpptrace/from_current.hpp diff --git a/include/cpptrace/cpptrace.hpp b/include/cpptrace/cpptrace.hpp index b492381..5e66418 100644 --- a/include/cpptrace/cpptrace.hpp +++ b/include/cpptrace/cpptrace.hpp @@ -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: diff --git a/include/cpptrace/from_current.hpp b/include/cpptrace/from_current.hpp new file mode 100644 index 0000000..3b1a6ff --- /dev/null +++ b/include/cpptrace/from_current.hpp @@ -0,0 +1,51 @@ +#include + +#include +#include +#include +#include + +#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 diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp index ddfcc76..272ceea 100644 --- a/src/cpptrace.cpp +++ b/src/cpptrace.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -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!!-------- "<name()<<" "<name()< new_vtable; + + void clobber_type_info(const std::type_info& info) { + void* type_info_pointer = const_cast(reinterpret_cast(&info)); + void* type_info_vtable_pointer = *reinterpret_cast(type_info_pointer); + type_info_vtable_pointer = reinterpret_cast(reinterpret_cast(type_info_vtable_pointer) - 2); // adjust offset + memcpy(new_vtable.data(), type_info_vtable_pointer, 11 * sizeof(void*)); + + new_vtable[6] = reinterpret_cast(foobar); + + if( + mprotect( + reinterpret_cast(reinterpret_cast(type_info_pointer) & ~(0xfffULL)), + 4096, + PROT_WRITE | PROT_READ + ) != 0 + ) { + perror("fuck"); + throw std::runtime_error("mprotect failed"); + } + *reinterpret_cast(type_info_pointer) = new_vtable.data() + 2; + if( + mprotect( + reinterpret_cast(reinterpret_cast(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(); + } } diff --git a/test/demo.cpp b/test/demo.cpp index 46ba38d..4581993 100644 --- a/test/demo.cpp +++ b/test/demo.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -6,9 +7,10 @@ #include 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: "<