1 /* 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 8 #include "CrashHandler.h" 9 10 #include "../private/SkLeanWindows.h" 11 12 #include <stdlib.h> 13 14 // Disable SetupCrashHandler() unless SK_CRASH_HANDLER is defined. 15 #ifndef SK_CRASH_HANDLER SetupCrashHandler()16 void SetupCrashHandler() { } 17 18 #elif defined(SK_BUILD_FOR_GOOGLE3) 19 #include "base/process_state.h" SetupCrashHandler()20 void SetupCrashHandler() { InstallSignalHandlers(); } 21 22 #else 23 24 #if defined(SK_BUILD_FOR_MAC) 25 26 // 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 handler(int sig)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 57 #elif defined(SK_BUILD_FOR_UNIX) 58 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 handler(int sig)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 77 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) 78 #include <signal.h> 79 SetupCrashHandler()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; 104 const DWORD code; 105 } 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 handler(EXCEPTION_POINTERS * e)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, 153 nullptr, 154 SymFunctionTableAccess64, 155 SymGetModuleBase64, 156 nullptr)) { 157 // 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 SetupCrashHandler()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 SetupCrashHandler()189 void SetupCrashHandler() { } 190 191 #endif 192 #endif // SK_CRASH_HANDLER 193