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