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