1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
diff --git a/cxxabi.h b/cxxabi.h
index e021f85..acf9974 100644
--- a/cxxabi.h
+++ b/cxxabi.h
@@ -249,6 +249,10 @@ char* __cxa_demangle(const char* mangled_name,
char* buf,
size_t* n,
int* status);
+
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+size_t __cxa_collect_current_exception_backtrace(void** dest, size_t size);
+#endif
#ifdef __cplusplus
} // extern "C"
} // namespace
diff --git a/exception.cc b/exception.cc
index 15f93ae..c4b15ae 100644
--- a/exception.cc
+++ b/exception.cc
@@ -255,12 +255,20 @@ namespace std
* various checks may test for equality of the class, which is incorrect.
*/
static const uint64_t exception_class =
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_PRIMARY_CLASS;
+#else
EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\0');
+#endif
/**
* Class used for dependent exceptions.
*/
static const uint64_t dependent_exception_class =
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_DEPENDENT_CLASS;
+#else
EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\x01');
+#endif
/**
* The low four bytes of the exception class, indicating that we conform to the
* Itanium C++ ABI. This is currently unused, but should be used in the future
@@ -605,6 +613,27 @@ static void free_exception(char *e)
}
#endif
+static constexpr size_t align_to(size_t size, size_t alignment) noexcept {
+ return (size + alignment - 1) / alignment * alignment;
+}
+
+static_assert(align_to(15, 16) == 16);
+static_assert(align_to(16, 16) == 16);
+static_assert(align_to(17, 16) == 32);
+
+static constexpr size_t exception_size = align_to(sizeof(__cxa_exception), 16);
+static constexpr size_t dependent_exception_size = align_to(sizeof(__cxa_dependent_exception), 16);
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+static constexpr size_t backtrace_buffer_size = align_to(sizeof(_Unwind_Backtrace_Buffer), 16);
+
+static_assert(
+ _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_MAGIC_OFFSET ==
+ offsetof(__cxa_exception, unwindHeader) + backtrace_buffer_size - sizeof(_Unwind_Backtrace_Buffer));
+#else
+static constexpr size_t backtrace_buffer_size = 0;
+#endif
+
+
/**
* Allocates an exception structure. Returns a pointer to the space that can
* be used to store an object of thrown_size bytes. This function will use an
@@ -613,16 +642,19 @@ static void free_exception(char *e)
*/
extern "C" void *__cxa_allocate_exception(size_t thrown_size) _LIBCXXRT_NOEXCEPT
{
- size_t size = thrown_size + sizeof(__cxa_exception);
+ size_t size = thrown_size + exception_size + backtrace_buffer_size;
char *buffer = alloc_or_die(size);
- return buffer+sizeof(__cxa_exception);
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ ((_Unwind_Backtrace_Buffer *)buffer)->size = 0;
+#endif
+ return buffer + exception_size + backtrace_buffer_size;
}
extern "C" void *__cxa_allocate_dependent_exception(void)
{
- size_t size = sizeof(__cxa_dependent_exception);
+ size_t size = dependent_exception_size + backtrace_buffer_size;
char *buffer = alloc_or_die(size);
- return buffer+sizeof(__cxa_dependent_exception);
+ return buffer + dependent_exception_size + backtrace_buffer_size;
}
/**
@@ -650,7 +682,8 @@ extern "C" void __cxa_free_exception(void *thrown_exception) _LIBCXXRT_NOEXCEPT
}
}
- free_exception(reinterpret_cast<char*>(ex));
+ free_exception(
+ reinterpret_cast<char*>(thrown_exception) - exception_size - backtrace_buffer_size);
}
static void releaseException(__cxa_exception *exception)
@@ -677,7 +710,7 @@ void __cxa_free_dependent_exception(void *thrown_exception)
{
releaseException(realExceptionFromException(reinterpret_cast<__cxa_exception*>(ex)));
}
- free_exception(reinterpret_cast<char*>(ex));
+ free_exception(reinterpret_cast<char*>(thrown_exception) - dependent_exception_size - backtrace_buffer_size);
}
/**
@@ -864,6 +897,32 @@ extern "C" void __cxa_decrement_exception_refcount(void* thrown_exception)
releaseException(ex);
}
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+static size_t __cxa_collect_backtrace(__cxa_exception* ex, void** dest, size_t size) {
+ if (!ex) {
+ return 0;
+ }
+ if (!isCXXException(ex->unwindHeader.exception_class)) {
+ return 0;
+ }
+ size_t i = 0;
+ if (isDependentException(ex->unwindHeader.exception_class)) {
+ i = __cxa_collect_backtrace(
+ (__cxa_exception *)((__cxa_dependent_exception *)ex)->primaryException - 1, dest, size);
+ }
+ _Unwind_Backtrace_Buffer* backtraceBuffer = (_Unwind_Backtrace_Buffer*)(
+ (char *)(ex + 1) - exception_size - backtrace_buffer_size);
+ for (size_t j = 0; i != size && j != backtraceBuffer->size; ++i, ++j) {
+ dest[i] = backtraceBuffer->backtrace[j];
+ }
+ return i;
+}
+
+extern "C" size_t __cxa_collect_current_exception_backtrace(void** dest, size_t size) {
+ return __cxa_collect_backtrace(__cxa_get_globals()->caughtExceptions, dest, size);
+}
+#endif
+
/**
* ABI function. Rethrows the current exception. Does not remove the
* exception from the stack or decrement its handler count - the compiler is
|