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
|
commit 6a570ad85b81eb53f0245268c7315409de2520e0
merge: b38db0d0c3651fa83d5bc81f795fde7680f72033 45a49d9b4df748ab9f2b1267f8183b6574fea206
author: eeight
date: 2021-02-24T23:44:48+03:00
revision: 7897977
IGNIETFERRO-603 Record exception backtraces during stack unwinding
REVIEW: 1637486
--- a/include/unwind.h
+++ b/include/unwind.h
@@ -396,6 +396,21 @@ extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc,
_Unwind_Personality_Fn pers);
#endif
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+
+#define _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_SIZE 128
+// NB. How to compute:
+// offsetof(__cxa_exception, unwindHeader) + (sizeof(_Unwind_Backtrace_Buffer) + 15) / 16 * 16 - sizeof(_Unwind_Backtrace_Buffer)
+// Correctness of this value is static_assert'd in contrib/libs/cxxsupp/libcxxrta/exception.cc
+#define _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_MAGIC_OFFSET 104
+#define _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_PRIMARY_CLASS 0xacadacadull
+#define _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_DEPENDENT_CLASS 0xddddacadull
+
+typedef struct _Unwind_Backtrace_Buffer {
+ size_t size;
+ void* backtrace[_YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_SIZE];
+} _Unwind_Backtrace_Buffer;
+#endif
#ifdef __cplusplus
}
#endif
--- a/src/UnwindLevel1.c
+++ b/src/UnwindLevel1.c
@@ -38,6 +38,15 @@ static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
__unw_init_local(cursor, uc);
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ _Unwind_Backtrace_Buffer* backtrace_buffer =
+ exception_object->exception_class == _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_PRIMARY_CLASS ||
+ exception_object->exception_class == _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_DEPENDENT_CLASS ?
+ (_Unwind_Backtrace_Buffer *)(
+ (char*)exception_object - _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_MAGIC_OFFSET) - 1
+ : NULL;
+#endif
+
// Walk each frame looking for a place to stop.
while (true) {
// Ask libunwind to get next frame (skip over first which is
@@ -57,6 +66,14 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
return _URC_FATAL_PHASE1_ERROR;
}
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ if (backtrace_buffer && backtrace_buffer->size < _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_SIZE) {
+ unw_word_t pc;
+ __unw_get_reg(cursor, UNW_REG_IP, &pc);
+ backtrace_buffer->backtrace[backtrace_buffer->size++] = (void *)pc;
+ }
+#endif
+
// See if frame has code to run (has personality routine).
unw_proc_info_t frameInfo;
unw_word_t sp;
|