Basic implementation for universal exception tracing on linux/itanium
This commit is contained in:
parent
2ae193256d
commit
d3d697f439
@ -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:
|
||||
|
||||
51
include/cpptrace/from_current.hpp
Normal file
51
include/cpptrace/from_current.hpp
Normal 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
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user