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