1 #include "CrashHandler.h" 2 3 #include "SkTypes.h" 4 5 #include <stdlib.h> 6 7 // Disable SetupCrashHandler() unless SK_CRASH_HANDLER is defined. 8 #ifndef SK_CRASH_HANDLER 9 void SetupCrashHandler() { } 10 11 #else 12 13 #if defined(SK_BUILD_FOR_MAC) 14 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 registered with atexit(). 43 _Exit(sig); 44 } 45 46 #elif defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_NACL) // NACL doesn'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 anyway. 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 registered 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 so (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 walking 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 the symbol. 158 DWORD64 offset; 159 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol); 160 161 SkDebugf("%s +%x\n", symbol->Name, offset); 162 } 163 164 // Exit NOW. Don't notify other threads, don't call anything registered 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 182