blob: f141e55407e47f05bc22505ec5a9191296805c41 [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
mtklein30e6e2a2014-06-18 11:44:15 -07008#include "CrashHandler.h"
9
halcanary4dbbd042016-06-07 17:21:10 -070010#include "../private/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
mtklein0e3fac22014-07-02 14:30:47 -070014// Disable SetupCrashHandler() unless SK_CRASH_HANDLER is defined.
15#ifndef SK_CRASH_HANDLER
16 void SetupCrashHandler() { }
mtklein30e6e2a2014-06-18 11:44:15 -070017
mtkleinb47bba72015-01-14 06:38:28 -080018#elif defined(GOOGLE3)
19 #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)
mtklein30e6e2a2014-06-18 11:44:15 -070025
mtklein0e3fac22014-07-02 14:30:47 -070026 // We only use local unwinding, so we can define this to select a faster implementation.
27 #define UNW_LOCAL_ONLY
28 #include <libunwind.h>
29 #include <cxxabi.h>
30
31 static void handler(int sig) {
32 unw_context_t context;
33 unw_getcontext(&context);
34
35 unw_cursor_t cursor;
36 unw_init_local(&cursor, &context);
37
38 SkDebugf("\nSignal %d:\n", sig);
39 while (unw_step(&cursor) > 0) {
40 static const size_t kMax = 256;
41 char mangled[kMax], demangled[kMax];
42 unw_word_t offset;
43 unw_get_proc_name(&cursor, mangled, kMax, &offset);
44
45 int ok;
46 size_t len = kMax;
47 abi::__cxa_demangle(mangled, demangled, &len, &ok);
48
49 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
50 }
51 SkDebugf("\n");
52
53 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
54 _Exit(sig);
55 }
56
borenet48087572015-04-02 12:16:36 -070057 #elif defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -070058
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 <execinfo.h>
62
63 static void handler(int sig) {
64 static const int kMax = 64;
65 void* stack[kMax];
66 const int count = backtrace(stack, kMax);
67
68 SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
69 backtrace_symbols_fd(stack, count, 2/*stderr*/);
70
71 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
72 _Exit(sig);
73 }
74
75 #endif
76
borenet48087572015-04-02 12:16:36 -070077 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
mtklein0e3fac22014-07-02 14:30:47 -070078 #include <signal.h>
79
80 void SetupCrashHandler() {
81 static const int kSignals[] = {
82 SIGABRT,
83 SIGBUS,
84 SIGFPE,
85 SIGILL,
86 SIGSEGV,
87 };
88
89 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
90 // Register our signal handler unless something's already done so (e.g. catchsegv).
91 void (*prev)(int) = signal(kSignals[i], handler);
92 if (prev != SIG_DFL) {
93 signal(kSignals[i], prev);
94 }
95 }
96 }
97
98 #elif defined(SK_CRASH_HANDLER) && defined(SK_BUILD_FOR_WIN)
99
100 #include <DbgHelp.h>
101
102 static const struct {
103 const char* name;
bungeman4ab57e02016-03-19 15:51:05 -0700104 const DWORD code;
mtklein0e3fac22014-07-02 14:30:47 -0700105 } kExceptions[] = {
106 #define _(E) {#E, E}
107 _(EXCEPTION_ACCESS_VIOLATION),
108 _(EXCEPTION_BREAKPOINT),
109 _(EXCEPTION_INT_DIVIDE_BY_ZERO),
110 _(EXCEPTION_STACK_OVERFLOW),
111 // TODO: more?
112 #undef _
113 };
114
115 static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
116 const DWORD code = e->ExceptionRecord->ExceptionCode;
117 SkDebugf("\nCaught exception %u", code);
118 for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
119 if (kExceptions[i].code == code) {
120 SkDebugf(" %s", kExceptions[i].name);
121 }
122 }
123 SkDebugf("\n");
124
125 // We need to run SymInitialize before doing any of the stack walking below.
126 HANDLE hProcess = GetCurrentProcess();
127 SymInitialize(hProcess, 0, true);
128
129 STACKFRAME64 frame;
130 sk_bzero(&frame, sizeof(frame));
131 // Start frame off from the frame that triggered the exception.
132 CONTEXT* c = e->ContextRecord;
133 frame.AddrPC.Mode = AddrModeFlat;
134 frame.AddrStack.Mode = AddrModeFlat;
135 frame.AddrFrame.Mode = AddrModeFlat;
136 #if defined(_X86_)
137 frame.AddrPC.Offset = c->Eip;
138 frame.AddrStack.Offset = c->Esp;
139 frame.AddrFrame.Offset = c->Ebp;
140 const DWORD machineType = IMAGE_FILE_MACHINE_I386;
141 #elif defined(_AMD64_)
142 frame.AddrPC.Offset = c->Rip;
143 frame.AddrStack.Offset = c->Rsp;
144 frame.AddrFrame.Offset = c->Rbp;
145 const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
146 #endif
147
148 while (StackWalk64(machineType,
149 GetCurrentProcess(),
150 GetCurrentThread(),
151 &frame,
152 c,
halcanary96fcdcc2015-08-27 07:41:13 -0700153 nullptr,
mtklein0e3fac22014-07-02 14:30:47 -0700154 SymFunctionTableAccess64,
155 SymGetModuleBase64,
halcanary96fcdcc2015-08-27 07:41:13 -0700156 nullptr)) {
mtklein0e3fac22014-07-02 14:30:47 -0700157 // Buffer to store symbol name in.
158 static const int kMaxNameLength = 1024;
159 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
160 sk_bzero(buffer, sizeof(buffer));
161
162 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
163 // how much space it can use.
164 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
165 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
166 symbol->MaxNameLength = kMaxNameLength - 1;
167
168 // Translate the current PC into a symbol and byte offset from the symbol.
169 DWORD64 offset;
170 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
171
172 SkDebugf("%s +%x\n", symbol->Name, offset);
173 }
174
175 // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
176 _exit(1);
177
178 // The compiler wants us to return something. This is what we'd do
179 // if we didn't _exit().
180 return EXCEPTION_EXECUTE_HANDLER;
181 }
182
183 void SetupCrashHandler() {
184 SetUnhandledExceptionFilter(handler);
185 }
186
187 #else // We asked for SK_CRASH_HANDLER, but it's not Mac, Linux, or Windows. Sorry!
188
189 void SetupCrashHandler() { }
190
191 #endif
192#endif // SK_CRASH_HANDLER