1 #include "CrashHandler.h" 2 3 #include "SkTypes.h" 4 5 #include <stdlib.h> 6 7 #if defined(SK_BUILD_FOR_MAC) 8 9 // We only use local unwinding, so we can define this to select a faster implementation. 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 with 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 with atexit(). 55 _Exit(sig); 56 } 57 58 #endif 59 60 #if defined(SK_BUILD_FOR_MAC) || (defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_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 symbol. 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 with atexit(). 158 _exit(1); 159 160 // The compiler wants us to return something. This is what we'd do if we didn't _exit(). 161 return EXCEPTION_EXECUTE_HANDLER; 162 } 163 164 void SetupCrashHandler() { 165 SetUnhandledExceptionFilter(handler); 166 } 167 168 #else 169 170 void SetupCrashHandler() { } 171 172 #endif 173