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