From: Mikko Rasa Date: Tue, 17 Sep 2019 14:22:55 +0000 (+0300) Subject: Add a facility to automatically create backtraces for exceptions X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=c7b4b9d6e07b3e32e5b03f41f0640a8273eed848;p=libs%2Fcore.git 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. --- 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