1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // crash_handler_posix:
7 // ANGLE's crash handling and stack walking code. Modified from Skia's:
8 // https://github.com/google/skia/blob/master/tools/CrashHandler.cpp
9 //
10
11 #include "util/test_utils.h"
12
13 #include "common/angleutils.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
19 # if defined(ANGLE_PLATFORM_APPLE)
20 // We only use local unwinding, so we can define this to select a faster implementation.
21 # define UNW_LOCAL_ONLY
22 # include <cxxabi.h>
23 # include <libunwind.h>
24 # include <signal.h>
25 # elif defined(ANGLE_PLATFORM_POSIX)
26 // We'd use libunwind here too, but it's a pain to get installed for
27 // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway.
28 # include <cxxabi.h>
29 # include <dlfcn.h>
30 # include <execinfo.h>
31 # include <signal.h>
32 # include <string.h>
33 # endif // defined(ANGLE_PLATFORM_APPLE)
34 #endif // !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
35
36 namespace angle
37 {
38 #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
39
PrintStackBacktrace()40 void PrintStackBacktrace()
41 {
42 // No implementations yet.
43 }
44
InitCrashHandler(CrashCallback * callback)45 void InitCrashHandler(CrashCallback *callback)
46 {
47 // No implementations yet.
48 }
49
TerminateCrashHandler()50 void TerminateCrashHandler()
51 {
52 // No implementations yet.
53 }
54
55 #else
56 namespace
57 {
58 CrashCallback *gCrashHandlerCallback;
59 } // namespace
60
61 # if defined(ANGLE_PLATFORM_APPLE)
62
63 void PrintStackBacktrace()
64 {
65 printf("Backtrace:\n");
66
67 unw_context_t context;
68 unw_getcontext(&context);
69
70 unw_cursor_t cursor;
71 unw_init_local(&cursor, &context);
72
73 while (unw_step(&cursor) > 0)
74 {
75 static const size_t kMax = 256;
76 char mangled[kMax], demangled[kMax];
77 unw_word_t offset;
78 unw_get_proc_name(&cursor, mangled, kMax, &offset);
79
80 int ok;
81 size_t len = kMax;
82 abi::__cxa_demangle(mangled, demangled, &len, &ok);
83
84 printf(" %s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
85 }
86 printf("\n");
87 }
88
89 static void Handler(int sig)
90 {
91 if (gCrashHandlerCallback)
92 {
93 (*gCrashHandlerCallback)();
94 }
95
96 printf("\nSignal %d:\n", sig);
97 PrintStackBacktrace();
98
99 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
100 _Exit(sig);
101 }
102
103 # elif defined(ANGLE_PLATFORM_POSIX)
104
105 void PrintStackBacktrace()
106 {
107 printf("Backtrace:\n");
108
109 void *stack[64];
110 const int count = backtrace(stack, ArraySize(stack));
111 char **symbols = backtrace_symbols(stack, count);
112
113 for (int i = 0; i < count; i++)
114 {
115 Dl_info info;
116 if (dladdr(stack[i], &info) && info.dli_sname)
117 {
118 // Make sure this is large enough to hold the fully demangled names, otherwise we could
119 // segault/hang here. For example, Vulkan validation layer errors can be deep enough
120 // into the stack that very large symbol names are generated.
121 char demangled[4096];
122 size_t len = ArraySize(demangled);
123 int ok;
124
125 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
126 if (ok == 0)
127 {
128 printf(" %s\n", demangled);
129 continue;
130 }
131 }
132 printf(" %s\n", symbols[i]);
133 }
134 }
135
136 static void Handler(int sig)
137 {
138 if (gCrashHandlerCallback)
139 {
140 (*gCrashHandlerCallback)();
141 }
142
143 printf("\nSignal %d [%s]:\n", sig, strsignal(sig));
144 PrintStackBacktrace();
145
146 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
147 _Exit(sig);
148 }
149
150 # endif // defined(ANGLE_PLATFORM_APPLE)
151
152 static constexpr int kSignals[] = {
153 SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP,
154 };
155
156 void InitCrashHandler(CrashCallback *callback)
157 {
158 gCrashHandlerCallback = callback;
159 for (int sig : kSignals)
160 {
161 // Register our signal handler unless something's already done so (e.g. catchsegv).
162 void (*prev)(int) = signal(sig, Handler);
163 if (prev != SIG_DFL)
164 {
165 signal(sig, prev);
166 }
167 }
168 }
169
170 void TerminateCrashHandler()
171 {
172 gCrashHandlerCallback = nullptr;
173 for (int sig : kSignals)
174 {
175 void (*prev)(int) = signal(sig, SIG_DFL);
176 if (prev != Handler && prev != SIG_DFL)
177 {
178 signal(sig, prev);
179 }
180 }
181 }
182
183 #endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA)
184
185 } // namespace angle
186