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