Flutter Engine
The Flutter Engine
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
sk_bzero(glyphs, sizeof(glyphs))
int count
Definition: FontMgrTest.cpp:50
static float prev(float f)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool ok(int result)
double frame
Definition: examples.cpp:31
__asm__(".symver expf,expf@GLIBC_2.4")
__attribute__((visibility("default"))) int RunBenchmarks(int argc
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SeparatedVector2 offset
long LONG
Definition: windows_types.h:23
#define WINAPI
void * HANDLE
Definition: windows_types.h:36
unsigned long DWORD
Definition: windows_types.h:22