From c7b4b9d6e07b3e32e5b03f41f0640a8273eed848 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 17 Sep 2019 17:22:55 +0300 Subject: [PATCH] Add a facility to automatically create backtraces for exceptions Obtaining a backtrace in the catch block won't show where the exception happened. Hooking into the exception handler internals is necessary. Because this is somewhat disruptive to the language runtime, it is an optional feature and disabled by default. --- Build | 2 + source/debug/exceptiontrace.cpp | 71 +++++++++++++++++++++++++++++++++ source/debug/exceptiontrace.h | 15 +++++++ 3 files changed, 88 insertions(+) create mode 100644 source/debug/exceptiontrace.cpp create mode 100644 source/debug/exceptiontrace.h diff --git a/Build b/Build index 12e3114..6ece10b 100644 --- a/Build +++ b/Build @@ -41,6 +41,8 @@ package "mspcore" require "zlib"; }; + feature "exception_trace" "Support exception backtraces"; + library "mspcore" { source "source/core"; diff --git a/source/debug/exceptiontrace.cpp b/source/debug/exceptiontrace.cpp new file mode 100644 index 0000000..30df4b6 --- /dev/null +++ b/source/debug/exceptiontrace.cpp @@ -0,0 +1,71 @@ +#include +#if !defined(_WIN32) && defined(__GLIBC__) +#include +#endif +#include "backtrace.h" +#include "exceptiontrace.h" + +using namespace std; + +namespace { + +#if defined(WITH_EXCEPTION_TRACE) && !defined(_WIN32) && defined(__GLIBC__) +typedef void CxaThrowType(void *, type_info *, void (*)(void *)); +CxaThrowType *orig_cxa_throw; + +struct HookThrow +{ + HookThrow(); +}; + +HookThrow::HookThrow() +{ + void *handle = dlopen(0, RTLD_LAZY); + orig_cxa_throw = reinterpret_cast(dlvsym(handle, "__cxa_throw", "CXXABI_1.3")); + dlclose(handle); +} + +HookThrow hook; +#endif + +bool trace_enabled = false; + +Msp::Debug::Backtrace &get_thread_backtrace() +{ +#if __cplusplus>=201103L + static thread_local Msp::Debug::Backtrace backtrace; +#elif defined(__GNUC__) + static __thread Msp::Debug::Backtrace backtrace; +#else + static Msp::Debug::Backtrace backtrace; +#endif + return backtrace; +} + +} + +namespace Msp { +namespace Debug { + +void enable_exception_trace(bool e) +{ + trace_enabled = e; +} + +const Backtrace &get_exception_trace() +{ + return get_thread_backtrace(); +} + +} // namespace Debug +} // namespace Msp + +#if defined(WITH_EXCEPTION_TRACE) && !defined(_WIN32) && defined(__GLIBC__) +extern "C" void __cxa_throw(void *exc, std::type_info *type, void (*dest) (void *)) +{ + if(trace_enabled) + get_thread_backtrace() = Msp::Debug::Backtrace::create(); + orig_cxa_throw(exc, type, dest); + std::terminate(); +} +#endif diff --git a/source/debug/exceptiontrace.h b/source/debug/exceptiontrace.h new file mode 100644 index 0000000..52664b6 --- /dev/null +++ b/source/debug/exceptiontrace.h @@ -0,0 +1,15 @@ +#ifndef MSP_DEBUG_EXCEPTIONTRACE_H_ +#define MSP_DEBUG_EXCEPTIONTRACE_H_ + +namespace Msp { +namespace Debug { + +class Backtrace; + +void enable_exception_trace(bool); +const Backtrace &get_exception_trace(); + +} // namespace Debug +} // namespace Msp + +#endif -- 2.43.0