Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
CrashHandler.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
12
13#include <array> // for std::size
14#include <stdlib.h>
15
16#if defined(SK_BUILD_FOR_GOOGLE3)
17 #include "base/config.h" // May define GOOGLE_ENABLE_SIGNAL_HANDLERS.
18#endif
19
20#if defined(GOOGLE_ENABLE_SIGNAL_HANDLERS)
21 #include "base/process_state.h"
22 void SetupCrashHandler() { InstallSignalHandlers(); }
23
24#else
25
26 #if defined(SK_BUILD_FOR_MAC)
27 // We only use local unwinding, so we can define this to select a faster implementation.
28 #define UNW_LOCAL_ONLY
29 #include <libunwind.h>
30 #include <cxxabi.h>
31
32 static void handler(int sig) {
33 unw_context_t context;
34 unw_getcontext(&context);
35
36 unw_cursor_t cursor;
37 unw_init_local(&cursor, &context);
38
39 SkDebugf("\nSignal %d:\n", sig);
40 while (unw_step(&cursor) > 0) {
41 static const size_t kMax = 256;
42 char mangled[kMax], demangled[kMax];
43 unw_word_t offset;
44 unw_get_proc_name(&cursor, mangled, kMax, &offset);
45
46 int ok;
47 size_t len = kMax;
48 abi::__cxa_demangle(mangled, demangled, &len, &ok);
49
50 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
51 }
52 SkDebugf("\n");
53
54 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
55 _Exit(sig);
56 }
57
58 #elif defined(SK_BUILD_FOR_UNIX)
59 // We'd use libunwind here too, but it's a pain to get installed for
60 // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway.
61 #include <cxxabi.h>
62 #include <dlfcn.h>
63 #include <string.h>
64#if defined(__Fuchsia__)
65 #include <stdint.h>
66
67 // syslog crash reporting from Fuchsia's backtrace_request.h
68 //
69 // Special value we put in the first register to let the exception handler know
70 // that we are just requesting a backtrace and we should resume the thread.
71 #define BACKTRACE_REQUEST_MAGIC ((uint64_t)0xee726573756d65ee)
72
73 // Prints a backtrace, resuming the thread without killing the process.
74 __attribute__((always_inline)) static inline void backtrace_request(void) {
75 // Two instructions: one that sets a software breakpoint ("int3" on x64,
76 // "brk" on arm64) and one that writes the "magic" value in the first
77 // register ("a" on x64, "x0" on arm64).
78 //
79 // We set a software breakpoint to trigger the exception handling in
80 // crashsvc, which will print the debug info, including the backtrace.
81 //
82 // We write the "magic" value in the first register so that the exception
83 // handler can check for it and resume the thread if present.
84 #ifdef __x86_64__
85 __asm__("int3" : : "a"(BACKTRACE_REQUEST_MAGIC));
86 #endif
87 #ifdef __aarch64__
88 // This is what gdb uses.
89 __asm__(
90 "mov x0, %0\n"
91 "\tbrk 0"
92 :
93 : "r"(BACKTRACE_REQUEST_MAGIC)
94 : "x0");
95 #endif
96 }
97#else
98 #include <execinfo.h>
99#endif
100
101 static void handler(int sig) {
102#if defined(__Fuchsia__)
103 backtrace_request();
104#else
105 void* stack[64];
106 const int count = backtrace(stack, std::size(stack));
107 char** symbols = backtrace_symbols(stack, count);
108
109 SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
110 for (int i = 0; i < count; i++) {
111 Dl_info info;
112 if (dladdr(stack[i], &info) && info.dli_sname) {
113 char demangled[256];
114 size_t len = std::size(demangled);
115 int ok;
116
117 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
118 if (ok == 0) {
119 SkDebugf(" %s\n", demangled);
120 continue;
121 }
122 }
123 SkDebugf(" %s\n", symbols[i]);
124 }
125#endif
126 // Exit NOW. Don't notify other threads, don't call anything registered with
127 // atexit().
128 _Exit(sig);
129 }
130 #endif
131
132 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
133 #include <signal.h>
134
135 void SetupCrashHandler() {
136 static const int kSignals[] = {
137 SIGABRT,
138 SIGBUS,
139 SIGFPE,
140 SIGILL,
141 SIGSEGV,
142 SIGTRAP,
143 };
144
145 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
146 // Register our signal handler unless something's already done so (e.g. catchsegv).
147 void (*prev)(int) = signal(kSignals[i], handler);
148 if (prev != SIG_DFL) {
149 signal(kSignals[i], prev);
150 }
151 }
152 }
153
154 #elif defined(SK_BUILD_FOR_WIN)
155
156 #include <DbgHelp.h>
157 #include <stdint.h>
159
160 static const struct {
161 const char* name;
162 const DWORD code;
163 } kExceptions[] = {
164 #define _(E) {#E, E}
165 _(EXCEPTION_ACCESS_VIOLATION),
166 _(EXCEPTION_BREAKPOINT),
167 _(EXCEPTION_INT_DIVIDE_BY_ZERO),
168 _(EXCEPTION_STACK_OVERFLOW),
169 // TODO: more?
170 #undef _
171 };
172
173 static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
174 const DWORD code = e->ExceptionRecord->ExceptionCode;
175 SkDebugf("\nCaught exception %lu", code);
176 for (size_t i = 0; i < std::size(kExceptions); i++) {
177 if (kExceptions[i].code == code) {
178 SkDebugf(" %s", kExceptions[i].name);
179 }
180 }
181 SkDebugf("\n");
182
183 // We need to run SymInitialize before doing any of the stack walking below.
184 HANDLE hProcess = GetCurrentProcess();
185 SymInitialize(hProcess, 0, true);
186
187 STACKFRAME64 frame;
188 sk_bzero(&frame, sizeof(frame));
189 // Start frame off from the frame that triggered the exception.
190 CONTEXT* c = e->ContextRecord;
191 frame.AddrPC.Mode = AddrModeFlat;
192 frame.AddrStack.Mode = AddrModeFlat;
193 frame.AddrFrame.Mode = AddrModeFlat;
194 #if defined(_X86_)
195 frame.AddrPC.Offset = c->Eip;
196 frame.AddrStack.Offset = c->Esp;
197 frame.AddrFrame.Offset = c->Ebp;
198 const DWORD machineType = IMAGE_FILE_MACHINE_I386;
199 #elif defined(_AMD64_)
200 frame.AddrPC.Offset = c->Rip;
201 frame.AddrStack.Offset = c->Rsp;
202 frame.AddrFrame.Offset = c->Rbp;
203 const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
204 #elif defined(_M_ARM64)
205 frame.AddrPC.Offset = c->Pc;
206 frame.AddrStack.Offset = c->Sp;
207 frame.AddrFrame.Offset = c->Fp;
208 const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
209 #endif
210
211 #if !defined(SK_WINUWP)
212 while (StackWalk64(machineType,
213 GetCurrentProcess(),
214 GetCurrentThread(),
215 &frame,
216 c,
217 nullptr,
218 SymFunctionTableAccess64,
219 SymGetModuleBase64,
220 nullptr)) {
221 // Buffer to store symbol name in.
222 static const int kMaxNameLength = 1024;
223 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
224 sk_bzero(buffer, sizeof(buffer));
225
226 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
227 // how much space it can use.
228 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
229 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
230 symbol->MaxNameLength = kMaxNameLength - 1;
231
232 // Translate the current PC into a symbol and byte offset from the symbol.
233 DWORD64 offset;
234 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
235
236 SkDebugf("%s +%llx\n", symbol->Name, offset);
237 }
238 #endif //SK_WINUWP
239
240 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
241 _exit(1);
242
243 // The compiler wants us to return something. This is what we'd do
244 // if we didn't _exit().
245 return EXCEPTION_EXECUTE_HANDLER;
246 }
247
248 void SetupCrashHandler() {
249 SetUnhandledExceptionFilter(handler);
250 }
251
252 #else
253
255
256 #endif
257#endif // SK_BUILD_FOR_GOOGLE3?
void SetupCrashHandler()
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
int count
static float prev(float f)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool ok(int result)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
Type::kYUV Type::kRGBA() int(0.7 *637)
double frame
Definition examples.cpp:31
static const uint8_t buffer[]
__asm__(".symver expf,expf@GLIBC_2.4")
const char * name
Definition fuchsia.cc:50
__attribute__((visibility("default"))) int RunBenchmarks(int argc
Point offset
long LONG
#define WINAPI
void * HANDLE
unsigned long DWORD