blob: c498820c39d90e4dc0242f238bc2769277dd1139 [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)
Mike Kleinc49da0b2020-10-16 16:20:28 -050015 #include "base/config.h" // May define GOOGLE_ENABLE_SIGNAL_HANDLERS.
16#endif
17
18#if defined(GOOGLE_ENABLE_SIGNAL_HANDLERS)
mtkleinb47bba72015-01-14 06:38:28 -080019 #include "base/process_state.h"
20 void SetupCrashHandler() { InstallSignalHandlers(); }
21
mtklein30e6e2a2014-06-18 11:44:15 -070022#else
23
mtklein0e3fac22014-07-02 14:30:47 -070024 #if defined(SK_BUILD_FOR_MAC)
mtklein0e3fac22014-07-02 14:30:47 -070025 // We only use local unwinding, so we can define this to select a faster implementation.
26 #define UNW_LOCAL_ONLY
27 #include <libunwind.h>
28 #include <cxxabi.h>
29
30 static void handler(int sig) {
31 unw_context_t context;
32 unw_getcontext(&context);
33
34 unw_cursor_t cursor;
35 unw_init_local(&cursor, &context);
36
37 SkDebugf("\nSignal %d:\n", sig);
38 while (unw_step(&cursor) > 0) {
39 static const size_t kMax = 256;
40 char mangled[kMax], demangled[kMax];
41 unw_word_t offset;
42 unw_get_proc_name(&cursor, mangled, kMax, &offset);
43
44 int ok;
45 size_t len = kMax;
46 abi::__cxa_demangle(mangled, demangled, &len, &ok);
47
48 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
49 }
50 SkDebugf("\n");
51
52 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
53 _Exit(sig);
54 }
55
borenet48087572015-04-02 12:16:36 -070056 #elif defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -070057 // We'd use libunwind here too, but it's a pain to get installed for
58 // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway.
Mike Kleinbf15b662019-04-15 11:32:16 -050059 #include <cxxabi.h>
60 #include <dlfcn.h>
Mike Kleinbf15b662019-04-15 11:32:16 -050061 #include <string.h>
John Rosasco24cbdab2019-09-25 14:14:35 -070062#if defined(__Fuchsia__)
63 #include <stdint.h>
64
65 // syslog crash reporting from Fuchsia's backtrace_request.h
66 //
67 // Special value we put in the first register to let the exception handler know
68 // that we are just requesting a backtrace and we should resume the thread.
69 #define BACKTRACE_REQUEST_MAGIC ((uint64_t)0xee726573756d65ee)
70
71 // Prints a backtrace, resuming the thread without killing the process.
72 __attribute__((always_inline)) static inline void backtrace_request(void) {
73 // Two instructions: one that sets a software breakpoint ("int3" on x64,
74 // "brk" on arm64) and one that writes the "magic" value in the first
75 // register ("a" on x64, "x0" on arm64).
76 //
77 // We set a software breakpoint to trigger the exception handling in
78 // crashsvc, which will print the debug info, including the backtrace.
79 //
80 // We write the "magic" value in the first register so that the exception
81 // handler can check for it and resume the thread if present.
82 #ifdef __x86_64__
83 __asm__("int3" : : "a"(BACKTRACE_REQUEST_MAGIC));
84 #endif
85 #ifdef __aarch64__
86 // This is what gdb uses.
87 __asm__(
88 "mov x0, %0\n"
89 "\tbrk 0"
90 :
91 : "r"(BACKTRACE_REQUEST_MAGIC)
92 : "x0");
93 #endif
94 }
95#else
96 #include <execinfo.h>
97#endif
mtklein0e3fac22014-07-02 14:30:47 -070098
99 static void handler(int sig) {
John Rosasco24cbdab2019-09-25 14:14:35 -0700100#if defined(__Fuchsia__)
101 backtrace_request();
102#else
Mike Kleinbf15b662019-04-15 11:32:16 -0500103 void* stack[64];
104 const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
105 char** symbols = backtrace_symbols(stack, count);
mtklein0e3fac22014-07-02 14:30:47 -0700106
107 SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
Mike Kleinbf15b662019-04-15 11:32:16 -0500108 for (int i = 0; i < count; i++) {
109 Dl_info info;
110 if (dladdr(stack[i], &info) && info.dli_sname) {
111 char demangled[256];
112 size_t len = SK_ARRAY_COUNT(demangled);
113 int ok;
114
115 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
116 if (ok == 0) {
117 SkDebugf(" %s\n", demangled);
118 continue;
119 }
120 }
121 SkDebugf(" %s\n", symbols[i]);
122 }
John Rosasco24cbdab2019-09-25 14:14:35 -0700123#endif
124 // Exit NOW. Don't notify other threads, don't call anything registered with
125 // atexit().
mtklein0e3fac22014-07-02 14:30:47 -0700126 _Exit(sig);
127 }
mtklein0e3fac22014-07-02 14:30:47 -0700128 #endif
129
borenet48087572015-04-02 12:16:36 -0700130 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -0700131 #include <signal.h>
132
133 void SetupCrashHandler() {
134 static const int kSignals[] = {
135 SIGABRT,
136 SIGBUS,
137 SIGFPE,
138 SIGILL,
139 SIGSEGV,
Mike Kleinbf15b662019-04-15 11:32:16 -0500140 SIGTRAP,
mtklein0e3fac22014-07-02 14:30:47 -0700141 };
142
143 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
144 // Register our signal handler unless something's already done so (e.g. catchsegv).
145 void (*prev)(int) = signal(kSignals[i], handler);
146 if (prev != SIG_DFL) {
147 signal(kSignals[i], prev);
148 }
149 }
150 }
151
Mike Kleinbf15b662019-04-15 11:32:16 -0500152 #elif defined(SK_BUILD_FOR_WIN)
mtklein0e3fac22014-07-02 14:30:47 -0700153
154 #include <DbgHelp.h>
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500155 #include "include/private/SkMalloc.h"
mtklein0e3fac22014-07-02 14:30:47 -0700156
157 static const struct {
158 const char* name;
bungeman4ab57e02016-03-19 15:51:05 -0700159 const DWORD code;
mtklein0e3fac22014-07-02 14:30:47 -0700160 } kExceptions[] = {
161 #define _(E) {#E, E}
162 _(EXCEPTION_ACCESS_VIOLATION),
163 _(EXCEPTION_BREAKPOINT),
164 _(EXCEPTION_INT_DIVIDE_BY_ZERO),
165 _(EXCEPTION_STACK_OVERFLOW),
166 // TODO: more?
167 #undef _
168 };
169
170 static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
171 const DWORD code = e->ExceptionRecord->ExceptionCode;
John Stiles7bf79992021-06-25 11:05:20 -0400172 SkDebugf("\nCaught exception %lu", code);
mtklein0e3fac22014-07-02 14:30:47 -0700173 for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
174 if (kExceptions[i].code == code) {
175 SkDebugf(" %s", kExceptions[i].name);
176 }
177 }
178 SkDebugf("\n");
179
180 // We need to run SymInitialize before doing any of the stack walking below.
181 HANDLE hProcess = GetCurrentProcess();
182 SymInitialize(hProcess, 0, true);
183
184 STACKFRAME64 frame;
185 sk_bzero(&frame, sizeof(frame));
186 // Start frame off from the frame that triggered the exception.
187 CONTEXT* c = e->ContextRecord;
188 frame.AddrPC.Mode = AddrModeFlat;
189 frame.AddrStack.Mode = AddrModeFlat;
190 frame.AddrFrame.Mode = AddrModeFlat;
191 #if defined(_X86_)
192 frame.AddrPC.Offset = c->Eip;
193 frame.AddrStack.Offset = c->Esp;
194 frame.AddrFrame.Offset = c->Ebp;
195 const DWORD machineType = IMAGE_FILE_MACHINE_I386;
196 #elif defined(_AMD64_)
197 frame.AddrPC.Offset = c->Rip;
198 frame.AddrStack.Offset = c->Rsp;
199 frame.AddrFrame.Offset = c->Rbp;
200 const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
Mike Kleind51d0072019-04-15 16:03:29 -0500201 #elif defined(_M_ARM64)
202 frame.AddrPC.Offset = c->Pc;
203 frame.AddrStack.Offset = c->Sp;
204 frame.AddrFrame.Offset = c->Fp;
205 const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
mtklein0e3fac22014-07-02 14:30:47 -0700206 #endif
207
James Clarkeb8c0dab2021-02-09 06:22:41 -0800208 #if !defined(SK_WINUWP)
mtklein0e3fac22014-07-02 14:30:47 -0700209 while (StackWalk64(machineType,
210 GetCurrentProcess(),
211 GetCurrentThread(),
212 &frame,
213 c,
halcanary96fcdcc2015-08-27 07:41:13 -0700214 nullptr,
mtklein0e3fac22014-07-02 14:30:47 -0700215 SymFunctionTableAccess64,
216 SymGetModuleBase64,
halcanary96fcdcc2015-08-27 07:41:13 -0700217 nullptr)) {
mtklein0e3fac22014-07-02 14:30:47 -0700218 // Buffer to store symbol name in.
219 static const int kMaxNameLength = 1024;
220 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
221 sk_bzero(buffer, sizeof(buffer));
222
223 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
224 // how much space it can use.
225 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
226 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
227 symbol->MaxNameLength = kMaxNameLength - 1;
228
229 // Translate the current PC into a symbol and byte offset from the symbol.
230 DWORD64 offset;
231 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
232
John Stiles7bf79992021-06-25 11:05:20 -0400233 SkDebugf("%s +%llx\n", symbol->Name, offset);
mtklein0e3fac22014-07-02 14:30:47 -0700234 }
James Clarkeb8c0dab2021-02-09 06:22:41 -0800235 #endif //SK_WINUWP
mtklein0e3fac22014-07-02 14:30:47 -0700236
237 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
238 _exit(1);
239
240 // The compiler wants us to return something. This is what we'd do
241 // if we didn't _exit().
242 return EXCEPTION_EXECUTE_HANDLER;
243 }
244
245 void SetupCrashHandler() {
246 SetUnhandledExceptionFilter(handler);
247 }
248
Mike Kleinbf15b662019-04-15 11:32:16 -0500249 #else
mtklein0e3fac22014-07-02 14:30:47 -0700250
251 void SetupCrashHandler() { }
252
253 #endif
Mike Kleinbf15b662019-04-15 11:32:16 -0500254#endif // SK_BUILD_FOR_GOOGLE3?