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