blob: c769ebcf12417f89f780b212c1a5ca3e644d9d2f [file] [log] [blame]
borenet48087572015-04-02 12:16:36 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tools/CrashHandler.h"
mtklein30e6e2a2014-06-18 11:44:15 -07009
Ben Wagnerab6eefe2019-05-20 11:02:49 -040010#include "src/core/SkLeanWindows.h"
mtklein30e6e2a2014-06-18 11:44:15 -070011
mtklein30e6e2a2014-06-18 11:44:15 -070012#include <stdlib.h>
mtklein30e6e2a2014-06-18 11:44:15 -070013
Mike Kleinbf15b662019-04-15 11:32:16 -050014#if defined(SK_BUILD_FOR_GOOGLE3)
mtkleinb47bba72015-01-14 06:38:28 -080015 #include "base/process_state.h"
16 void SetupCrashHandler() { InstallSignalHandlers(); }
17
mtklein30e6e2a2014-06-18 11:44:15 -070018#else
19
mtklein0e3fac22014-07-02 14:30:47 -070020 #if defined(SK_BUILD_FOR_MAC)
mtklein0e3fac22014-07-02 14:30:47 -070021 // We only use local unwinding, so we can define this to select a faster implementation.
22 #define UNW_LOCAL_ONLY
23 #include <libunwind.h>
24 #include <cxxabi.h>
25
26 static void handler(int sig) {
27 unw_context_t context;
28 unw_getcontext(&context);
29
30 unw_cursor_t cursor;
31 unw_init_local(&cursor, &context);
32
33 SkDebugf("\nSignal %d:\n", sig);
34 while (unw_step(&cursor) > 0) {
35 static const size_t kMax = 256;
36 char mangled[kMax], demangled[kMax];
37 unw_word_t offset;
38 unw_get_proc_name(&cursor, mangled, kMax, &offset);
39
40 int ok;
41 size_t len = kMax;
42 abi::__cxa_demangle(mangled, demangled, &len, &ok);
43
44 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
45 }
46 SkDebugf("\n");
47
48 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
49 _Exit(sig);
50 }
51
borenet48087572015-04-02 12:16:36 -070052 #elif defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -070053 // We'd use libunwind here too, but it's a pain to get installed for
54 // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway.
Mike Kleinbf15b662019-04-15 11:32:16 -050055 #include <cxxabi.h>
56 #include <dlfcn.h>
Mike Kleinbf15b662019-04-15 11:32:16 -050057 #include <string.h>
John Rosasco24cbdab2019-09-25 14:14:35 -070058#if defined(__Fuchsia__)
59 #include <stdint.h>
60
61 // syslog crash reporting from Fuchsia's backtrace_request.h
62 //
63 // Special value we put in the first register to let the exception handler know
64 // that we are just requesting a backtrace and we should resume the thread.
65 #define BACKTRACE_REQUEST_MAGIC ((uint64_t)0xee726573756d65ee)
66
67 // Prints a backtrace, resuming the thread without killing the process.
68 __attribute__((always_inline)) static inline void backtrace_request(void) {
69 // Two instructions: one that sets a software breakpoint ("int3" on x64,
70 // "brk" on arm64) and one that writes the "magic" value in the first
71 // register ("a" on x64, "x0" on arm64).
72 //
73 // We set a software breakpoint to trigger the exception handling in
74 // crashsvc, which will print the debug info, including the backtrace.
75 //
76 // We write the "magic" value in the first register so that the exception
77 // handler can check for it and resume the thread if present.
78 #ifdef __x86_64__
79 __asm__("int3" : : "a"(BACKTRACE_REQUEST_MAGIC));
80 #endif
81 #ifdef __aarch64__
82 // This is what gdb uses.
83 __asm__(
84 "mov x0, %0\n"
85 "\tbrk 0"
86 :
87 : "r"(BACKTRACE_REQUEST_MAGIC)
88 : "x0");
89 #endif
90 }
91#else
92 #include <execinfo.h>
93#endif
mtklein0e3fac22014-07-02 14:30:47 -070094
95 static void handler(int sig) {
John Rosasco24cbdab2019-09-25 14:14:35 -070096#if defined(__Fuchsia__)
97 backtrace_request();
98#else
Mike Kleinbf15b662019-04-15 11:32:16 -050099 void* stack[64];
100 const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
101 char** symbols = backtrace_symbols(stack, count);
mtklein0e3fac22014-07-02 14:30:47 -0700102
103 SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
Mike Kleinbf15b662019-04-15 11:32:16 -0500104 for (int i = 0; i < count; i++) {
105 Dl_info info;
106 if (dladdr(stack[i], &info) && info.dli_sname) {
107 char demangled[256];
108 size_t len = SK_ARRAY_COUNT(demangled);
109 int ok;
110
111 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
112 if (ok == 0) {
113 SkDebugf(" %s\n", demangled);
114 continue;
115 }
116 }
117 SkDebugf(" %s\n", symbols[i]);
118 }
John Rosasco24cbdab2019-09-25 14:14:35 -0700119#endif
120 // Exit NOW. Don't notify other threads, don't call anything registered with
121 // atexit().
mtklein0e3fac22014-07-02 14:30:47 -0700122 _Exit(sig);
123 }
mtklein0e3fac22014-07-02 14:30:47 -0700124 #endif
125
borenet48087572015-04-02 12:16:36 -0700126 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -0700127 #include <signal.h>
128
129 void SetupCrashHandler() {
130 static const int kSignals[] = {
131 SIGABRT,
132 SIGBUS,
133 SIGFPE,
134 SIGILL,
135 SIGSEGV,
Mike Kleinbf15b662019-04-15 11:32:16 -0500136 SIGTRAP,
mtklein0e3fac22014-07-02 14:30:47 -0700137 };
138
139 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
140 // Register our signal handler unless something's already done so (e.g. catchsegv).
141 void (*prev)(int) = signal(kSignals[i], handler);
142 if (prev != SIG_DFL) {
143 signal(kSignals[i], prev);
144 }
145 }
146 }
147
Mike Kleinbf15b662019-04-15 11:32:16 -0500148 #elif defined(SK_BUILD_FOR_WIN)
mtklein0e3fac22014-07-02 14:30:47 -0700149
150 #include <DbgHelp.h>
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500151 #include "include/private/SkMalloc.h"
mtklein0e3fac22014-07-02 14:30:47 -0700152
153 static const struct {
154 const char* name;
bungeman4ab57e02016-03-19 15:51:05 -0700155 const DWORD code;
mtklein0e3fac22014-07-02 14:30:47 -0700156 } kExceptions[] = {
157 #define _(E) {#E, E}
158 _(EXCEPTION_ACCESS_VIOLATION),
159 _(EXCEPTION_BREAKPOINT),
160 _(EXCEPTION_INT_DIVIDE_BY_ZERO),
161 _(EXCEPTION_STACK_OVERFLOW),
162 // TODO: more?
163 #undef _
164 };
165
166 static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
167 const DWORD code = e->ExceptionRecord->ExceptionCode;
168 SkDebugf("\nCaught exception %u", code);
169 for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
170 if (kExceptions[i].code == code) {
171 SkDebugf(" %s", kExceptions[i].name);
172 }
173 }
174 SkDebugf("\n");
175
176 // We need to run SymInitialize before doing any of the stack walking below.
177 HANDLE hProcess = GetCurrentProcess();
178 SymInitialize(hProcess, 0, true);
179
180 STACKFRAME64 frame;
181 sk_bzero(&frame, sizeof(frame));
182 // Start frame off from the frame that triggered the exception.
183 CONTEXT* c = e->ContextRecord;
184 frame.AddrPC.Mode = AddrModeFlat;
185 frame.AddrStack.Mode = AddrModeFlat;
186 frame.AddrFrame.Mode = AddrModeFlat;
187 #if defined(_X86_)
188 frame.AddrPC.Offset = c->Eip;
189 frame.AddrStack.Offset = c->Esp;
190 frame.AddrFrame.Offset = c->Ebp;
191 const DWORD machineType = IMAGE_FILE_MACHINE_I386;
192 #elif defined(_AMD64_)
193 frame.AddrPC.Offset = c->Rip;
194 frame.AddrStack.Offset = c->Rsp;
195 frame.AddrFrame.Offset = c->Rbp;
196 const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
Mike Kleind51d0072019-04-15 16:03:29 -0500197 #elif defined(_M_ARM64)
198 frame.AddrPC.Offset = c->Pc;
199 frame.AddrStack.Offset = c->Sp;
200 frame.AddrFrame.Offset = c->Fp;
201 const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
mtklein0e3fac22014-07-02 14:30:47 -0700202 #endif
203
204 while (StackWalk64(machineType,
205 GetCurrentProcess(),
206 GetCurrentThread(),
207 &frame,
208 c,
halcanary96fcdcc2015-08-27 07:41:13 -0700209 nullptr,
mtklein0e3fac22014-07-02 14:30:47 -0700210 SymFunctionTableAccess64,
211 SymGetModuleBase64,
halcanary96fcdcc2015-08-27 07:41:13 -0700212 nullptr)) {
mtklein0e3fac22014-07-02 14:30:47 -0700213 // Buffer to store symbol name in.
214 static const int kMaxNameLength = 1024;
215 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
216 sk_bzero(buffer, sizeof(buffer));
217
218 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
219 // how much space it can use.
220 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
221 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
222 symbol->MaxNameLength = kMaxNameLength - 1;
223
224 // Translate the current PC into a symbol and byte offset from the symbol.
225 DWORD64 offset;
226 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
227
228 SkDebugf("%s +%x\n", symbol->Name, offset);
229 }
230
231 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
232 _exit(1);
233
234 // The compiler wants us to return something. This is what we'd do
235 // if we didn't _exit().
236 return EXCEPTION_EXECUTE_HANDLER;
237 }
238
239 void SetupCrashHandler() {
240 SetUnhandledExceptionFilter(handler);
241 }
242
Mike Kleinbf15b662019-04-15 11:32:16 -0500243 #else
mtklein0e3fac22014-07-02 14:30:47 -0700244
245 void SetupCrashHandler() { }
246
247 #endif
Mike Kleinbf15b662019-04-15 11:32:16 -0500248#endif // SK_BUILD_FOR_GOOGLE3?