blob: 5a2186f6d577e5c58f16a4ffc6783a57d149edc5 [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>
mtklein0e3fac22014-07-02 14:30:47 -070057 #include <execinfo.h>
Mike Kleinbf15b662019-04-15 11:32:16 -050058 #include <string.h>
mtklein0e3fac22014-07-02 14:30:47 -070059
60 static void handler(int sig) {
Mike Kleinbf15b662019-04-15 11:32:16 -050061 void* stack[64];
62 const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
63 char** symbols = backtrace_symbols(stack, count);
mtklein0e3fac22014-07-02 14:30:47 -070064
65 SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
Mike Kleinbf15b662019-04-15 11:32:16 -050066 for (int i = 0; i < count; i++) {
67 Dl_info info;
68 if (dladdr(stack[i], &info) && info.dli_sname) {
69 char demangled[256];
70 size_t len = SK_ARRAY_COUNT(demangled);
71 int ok;
72
73 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
74 if (ok == 0) {
75 SkDebugf(" %s\n", demangled);
76 continue;
77 }
78 }
79 SkDebugf(" %s\n", symbols[i]);
80 }
mtklein0e3fac22014-07-02 14:30:47 -070081
82 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
83 _Exit(sig);
84 }
85
86 #endif
87
borenet48087572015-04-02 12:16:36 -070088 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -070089 #include <signal.h>
90
91 void SetupCrashHandler() {
92 static const int kSignals[] = {
93 SIGABRT,
94 SIGBUS,
95 SIGFPE,
96 SIGILL,
97 SIGSEGV,
Mike Kleinbf15b662019-04-15 11:32:16 -050098 SIGTRAP,
mtklein0e3fac22014-07-02 14:30:47 -070099 };
100
101 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
102 // Register our signal handler unless something's already done so (e.g. catchsegv).
103 void (*prev)(int) = signal(kSignals[i], handler);
104 if (prev != SIG_DFL) {
105 signal(kSignals[i], prev);
106 }
107 }
108 }
109
Mike Kleinbf15b662019-04-15 11:32:16 -0500110 #elif defined(SK_BUILD_FOR_WIN)
mtklein0e3fac22014-07-02 14:30:47 -0700111
112 #include <DbgHelp.h>
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500113 #include "include/private/SkMalloc.h"
mtklein0e3fac22014-07-02 14:30:47 -0700114
115 static const struct {
116 const char* name;
bungeman4ab57e02016-03-19 15:51:05 -0700117 const DWORD code;
mtklein0e3fac22014-07-02 14:30:47 -0700118 } kExceptions[] = {
119 #define _(E) {#E, E}
120 _(EXCEPTION_ACCESS_VIOLATION),
121 _(EXCEPTION_BREAKPOINT),
122 _(EXCEPTION_INT_DIVIDE_BY_ZERO),
123 _(EXCEPTION_STACK_OVERFLOW),
124 // TODO: more?
125 #undef _
126 };
127
128 static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
129 const DWORD code = e->ExceptionRecord->ExceptionCode;
130 SkDebugf("\nCaught exception %u", code);
131 for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
132 if (kExceptions[i].code == code) {
133 SkDebugf(" %s", kExceptions[i].name);
134 }
135 }
136 SkDebugf("\n");
137
138 // We need to run SymInitialize before doing any of the stack walking below.
139 HANDLE hProcess = GetCurrentProcess();
140 SymInitialize(hProcess, 0, true);
141
142 STACKFRAME64 frame;
143 sk_bzero(&frame, sizeof(frame));
144 // Start frame off from the frame that triggered the exception.
145 CONTEXT* c = e->ContextRecord;
146 frame.AddrPC.Mode = AddrModeFlat;
147 frame.AddrStack.Mode = AddrModeFlat;
148 frame.AddrFrame.Mode = AddrModeFlat;
149 #if defined(_X86_)
150 frame.AddrPC.Offset = c->Eip;
151 frame.AddrStack.Offset = c->Esp;
152 frame.AddrFrame.Offset = c->Ebp;
153 const DWORD machineType = IMAGE_FILE_MACHINE_I386;
154 #elif defined(_AMD64_)
155 frame.AddrPC.Offset = c->Rip;
156 frame.AddrStack.Offset = c->Rsp;
157 frame.AddrFrame.Offset = c->Rbp;
158 const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
Mike Kleind51d0072019-04-15 16:03:29 -0500159 #elif defined(_M_ARM64)
160 frame.AddrPC.Offset = c->Pc;
161 frame.AddrStack.Offset = c->Sp;
162 frame.AddrFrame.Offset = c->Fp;
163 const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
mtklein0e3fac22014-07-02 14:30:47 -0700164 #endif
165
166 while (StackWalk64(machineType,
167 GetCurrentProcess(),
168 GetCurrentThread(),
169 &frame,
170 c,
halcanary96fcdcc2015-08-27 07:41:13 -0700171 nullptr,
mtklein0e3fac22014-07-02 14:30:47 -0700172 SymFunctionTableAccess64,
173 SymGetModuleBase64,
halcanary96fcdcc2015-08-27 07:41:13 -0700174 nullptr)) {
mtklein0e3fac22014-07-02 14:30:47 -0700175 // Buffer to store symbol name in.
176 static const int kMaxNameLength = 1024;
177 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
178 sk_bzero(buffer, sizeof(buffer));
179
180 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
181 // how much space it can use.
182 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
183 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
184 symbol->MaxNameLength = kMaxNameLength - 1;
185
186 // Translate the current PC into a symbol and byte offset from the symbol.
187 DWORD64 offset;
188 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
189
190 SkDebugf("%s +%x\n", symbol->Name, offset);
191 }
192
193 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
194 _exit(1);
195
196 // The compiler wants us to return something. This is what we'd do
197 // if we didn't _exit().
198 return EXCEPTION_EXECUTE_HANDLER;
199 }
200
201 void SetupCrashHandler() {
202 SetUnhandledExceptionFilter(handler);
203 }
204
Mike Kleinbf15b662019-04-15 11:32:16 -0500205 #else
mtklein0e3fac22014-07-02 14:30:47 -0700206
207 void SetupCrashHandler() { }
208
209 #endif
Mike Kleinbf15b662019-04-15 11:32:16 -0500210#endif // SK_BUILD_FOR_GOOGLE3?