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