Add a facility to automatically create backtraces for exceptions
[libs/core.git] / source / debug / exceptiontrace.cpp
1 #include <string>
2 #if !defined(_WIN32) && defined(__GLIBC__)
3 #include <dlfcn.h>
4 #endif
5 #include "backtrace.h"
6 #include "exceptiontrace.h"
7
8 using namespace std;
9
10 namespace {
11
12 #if defined(WITH_EXCEPTION_TRACE) && !defined(_WIN32) && defined(__GLIBC__)
13 typedef void CxaThrowType(void *, type_info *, void (*)(void *));
14 CxaThrowType *orig_cxa_throw;
15
16 struct HookThrow
17 {
18         HookThrow();
19 };
20
21 HookThrow::HookThrow()
22 {
23         void *handle = dlopen(0, RTLD_LAZY);
24         orig_cxa_throw = reinterpret_cast<CxaThrowType *>(dlvsym(handle, "__cxa_throw", "CXXABI_1.3"));
25         dlclose(handle);
26 }
27
28 HookThrow hook;
29 #endif
30
31 bool trace_enabled = false;
32
33 Msp::Debug::Backtrace &get_thread_backtrace()
34 {
35 #if __cplusplus>=201103L
36         static thread_local Msp::Debug::Backtrace backtrace;
37 #elif defined(__GNUC__)
38         static __thread Msp::Debug::Backtrace backtrace;
39 #else
40         static Msp::Debug::Backtrace backtrace;
41 #endif
42         return backtrace;
43 }
44
45 }
46
47 namespace Msp {
48 namespace Debug {
49
50 void enable_exception_trace(bool e)
51 {
52         trace_enabled = e;
53 }
54
55 const Backtrace &get_exception_trace()
56 {
57         return get_thread_backtrace();
58 }
59
60 } // namespace Debug
61 } // namespace Msp
62
63 #if defined(WITH_EXCEPTION_TRACE) && !defined(_WIN32) && defined(__GLIBC__)
64 extern "C" void __cxa_throw(void *exc, std::type_info *type, void (*dest) (void *))
65 {
66         if(trace_enabled)
67                 get_thread_backtrace() = Msp::Debug::Backtrace::create();
68         orig_cxa_throw(exc, type, dest);
69         std::terminate();
70 }
71 #endif