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