]> git.tdb.fi Git - libs/core.git/blobdiff - source/debug/exceptiontrace.cpp
Add a facility to automatically create backtraces for exceptions
[libs/core.git] / source / debug / exceptiontrace.cpp
diff --git a/source/debug/exceptiontrace.cpp b/source/debug/exceptiontrace.cpp
new file mode 100644 (file)
index 0000000..30df4b6
--- /dev/null
@@ -0,0 +1,71 @@
+#include <string>
+#if !defined(_WIN32) && defined(__GLIBC__)
+#include <dlfcn.h>
+#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<CxaThrowType *>(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