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/config.h" // May define GOOGLE_ENABLE_SIGNAL_HANDLERS. 16 #endif 17 18 #if defined(GOOGLE_ENABLE_SIGNAL_HANDLERS) 19 #include "base/process_state.h" SetupCrashHandler()20 void SetupCrashHandler() { InstallSignalHandlers(); } 21 22 #else 23 24 #if defined(SK_BUILD_FOR_MAC) 25 // We only use local unwinding, so we can define this to select a faster implementation. 26 #define UNW_LOCAL_ONLY 27 #include <libunwind.h> 28 #include <cxxabi.h> 29 handler(int sig)30 static void handler(int sig) { 31 unw_context_t context; 32 unw_getcontext(&context); 33 34 unw_cursor_t cursor; 35 unw_init_local(&cursor, &context); 36 37 SkDebugf("\nSignal %d:\n", sig); 38 while (unw_step(&cursor) > 0) { 39 static const size_t kMax = 256; 40 char mangled[kMax], demangled[kMax]; 41 unw_word_t offset; 42 unw_get_proc_name(&cursor, mangled, kMax, &offset); 43 44 int ok; 45 size_t len = kMax; 46 abi::__cxa_demangle(mangled, demangled, &len, &ok); 47 48 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset); 49 } 50 SkDebugf("\n"); 51 52 // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). 53 _Exit(sig); 54 } 55 56 #elif defined(SK_BUILD_FOR_UNIX) 57 // We'd use libunwind here too, but it's a pain to get installed for 58 // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway. 59 #include <cxxabi.h> 60 #include <dlfcn.h> 61 #include <string.h> 62 #if defined(__Fuchsia__) 63 #include <stdint.h> 64 65 // syslog crash reporting from Fuchsia's backtrace_request.h 66 // 67 // Special value we put in the first register to let the exception handler know 68 // that we are just requesting a backtrace and we should resume the thread. 69 #define BACKTRACE_REQUEST_MAGIC ((uint64_t)0xee726573756d65ee) 70 71 // Prints a backtrace, resuming the thread without killing the process. backtrace_request(void)72 __attribute__((always_inline)) static inline void backtrace_request(void) { 73 // Two instructions: one that sets a software breakpoint ("int3" on x64, 74 // "brk" on arm64) and one that writes the "magic" value in the first 75 // register ("a" on x64, "x0" on arm64). 76 // 77 // We set a software breakpoint to trigger the exception handling in 78 // crashsvc, which will print the debug info, including the backtrace. 79 // 80 // We write the "magic" value in the first register so that the exception 81 // handler can check for it and resume the thread if present. 82 #ifdef __x86_64__ 83 __asm__("int3" : : "a"(BACKTRACE_REQUEST_MAGIC)); 84 #endif 85 #ifdef __aarch64__ 86 // This is what gdb uses. 87 __asm__( 88 "mov x0, %0\n" 89 "\tbrk 0" 90 : 91 : "r"(BACKTRACE_REQUEST_MAGIC) 92 : "x0"); 93 #endif 94 } 95 #else 96 #include <execinfo.h> 97 #endif 98 handler(int sig)99 static void handler(int sig) { 100 #if defined(__Fuchsia__) 101 backtrace_request(); 102 #else 103 void* stack[64]; 104 const int count = backtrace(stack, SK_ARRAY_COUNT(stack)); 105 char** symbols = backtrace_symbols(stack, count); 106 107 SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig)); 108 for (int i = 0; i < count; i++) { 109 Dl_info info; 110 if (dladdr(stack[i], &info) && info.dli_sname) { 111 char demangled[256]; 112 size_t len = SK_ARRAY_COUNT(demangled); 113 int ok; 114 115 abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok); 116 if (ok == 0) { 117 SkDebugf(" %s\n", demangled); 118 continue; 119 } 120 } 121 SkDebugf(" %s\n", symbols[i]); 122 } 123 #endif 124 // Exit NOW. Don't notify other threads, don't call anything registered with 125 // atexit(). 126 _Exit(sig); 127 } 128 #endif 129 130 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) 131 #include <signal.h> 132 SetupCrashHandler()133 void SetupCrashHandler() { 134 static const int kSignals[] = { 135 SIGABRT, 136 SIGBUS, 137 SIGFPE, 138 SIGILL, 139 SIGSEGV, 140 SIGTRAP, 141 }; 142 143 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) { 144 // Register our signal handler unless something's already done so (e.g. catchsegv). 145 void (*prev)(int) = signal(kSignals[i], handler); 146 if (prev != SIG_DFL) { 147 signal(kSignals[i], prev); 148 } 149 } 150 } 151 152 /* 153 #elif defined(SK_BUILD_FOR_WIN) 154 155 #include <DbgHelp.h> 156 #include "include/private/SkMalloc.h" 157 158 static const struct { 159 const char* name; 160 const DWORD code; 161 } kExceptions[] = { 162 #define _(E) {#E, E} 163 _(EXCEPTION_ACCESS_VIOLATION), 164 _(EXCEPTION_BREAKPOINT), 165 _(EXCEPTION_INT_DIVIDE_BY_ZERO), 166 _(EXCEPTION_STACK_OVERFLOW), 167 // TODO: more? 168 #undef _ 169 }; 170 171 static LONG WINAPI handler(EXCEPTION_POINTERS* e) { 172 const DWORD code = e->ExceptionRecord->ExceptionCode; 173 SkDebugf("\nCaught exception %lu", code); 174 for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) { 175 if (kExceptions[i].code == code) { 176 SkDebugf(" %s", kExceptions[i].name); 177 } 178 } 179 SkDebugf("\n"); 180 181 // We need to run SymInitialize before doing any of the stack walking below. 182 HANDLE hProcess = GetCurrentProcess(); 183 SymInitialize(hProcess, 0, true); 184 185 STACKFRAME64 frame; 186 sk_bzero(&frame, sizeof(frame)); 187 // Start frame off from the frame that triggered the exception. 188 CONTEXT* c = e->ContextRecord; 189 frame.AddrPC.Mode = AddrModeFlat; 190 frame.AddrStack.Mode = AddrModeFlat; 191 frame.AddrFrame.Mode = AddrModeFlat; 192 #if defined(_X86_) 193 frame.AddrPC.Offset = c->Eip; 194 frame.AddrStack.Offset = c->Esp; 195 frame.AddrFrame.Offset = c->Ebp; 196 const DWORD machineType = IMAGE_FILE_MACHINE_I386; 197 #elif defined(_AMD64_) 198 frame.AddrPC.Offset = c->Rip; 199 frame.AddrStack.Offset = c->Rsp; 200 frame.AddrFrame.Offset = c->Rbp; 201 const DWORD machineType = IMAGE_FILE_MACHINE_AMD64; 202 #elif defined(_M_ARM64) 203 frame.AddrPC.Offset = c->Pc; 204 frame.AddrStack.Offset = c->Sp; 205 frame.AddrFrame.Offset = c->Fp; 206 const DWORD machineType = IMAGE_FILE_MACHINE_ARM64; 207 #endif 208 209 #if !defined(SK_WINUWP) 210 while (StackWalk64(machineType, 211 GetCurrentProcess(), 212 GetCurrentThread(), 213 &frame, 214 c, 215 nullptr, 216 SymFunctionTableAccess64, 217 SymGetModuleBase64, 218 nullptr)) { 219 // Buffer to store symbol name in. 220 static const int kMaxNameLength = 1024; 221 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength]; 222 sk_bzero(buffer, sizeof(buffer)); 223 224 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in 225 // how much space it can use. 226 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer); 227 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 228 symbol->MaxNameLength = kMaxNameLength - 1; 229 230 // Translate the current PC into a symbol and byte offset from the symbol. 231 DWORD64 offset; 232 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol); 233 234 SkDebugf("%s +%llx\n", symbol->Name, offset); 235 } 236 #endif //SK_WINUWP 237 238 // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). 239 _exit(1); 240 241 // The compiler wants us to return something. This is what we'd do 242 // if we didn't _exit(). 243 return EXCEPTION_EXECUTE_HANDLER; 244 } 245 246 void SetupCrashHandler() { 247 SetUnhandledExceptionFilter(handler); 248 } 249 */ 250 251 #else 252 SetupCrashHandler()253 void SetupCrashHandler() { } 254 255 #endif 256 #endif // SK_BUILD_FOR_GOOGLE3? 257