Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #include "CrashHandler.h" | 1 #include "CrashHandler.h" |
| 2 | 2 |
| 3 #include "SkTypes.h" | 3 #include "SkTypes.h" |
| 4 | 4 |
| 5 #include <stdio.h> | |
| 6 #include <stdlib.h> | 5 #include <stdlib.h> |
| 7 #include <signal.h> | |
| 8 | 6 |
| 9 #if defined(SK_BUILD_FOR_MAC) | 7 #if defined(SK_BUILD_FOR_MAC) |
| 10 | 8 |
| 11 // We only use local unwinding, so we can define this to select a faster impleme ntation. | 9 // We only use local unwinding, so we can define this to select a faster impleme ntation. |
| 12 #define UNW_LOCAL_ONLY | 10 #define UNW_LOCAL_ONLY |
| 13 #include <libunwind.h> | 11 #include <libunwind.h> |
| 14 #include <cxxabi.h> | 12 #include <cxxabi.h> |
| 15 | 13 |
| 16 static void handler(int sig) { | 14 static void handler(int sig) { |
| 17 unw_context_t context; | 15 unw_context_t context; |
| 18 unw_getcontext(&context); | 16 unw_getcontext(&context); |
| 19 | 17 |
| 20 unw_cursor_t cursor; | 18 unw_cursor_t cursor; |
| 21 unw_init_local(&cursor, &context); | 19 unw_init_local(&cursor, &context); |
| 22 | 20 |
| 23 fprintf(stderr, "\nSignal %d:\n", sig); | 21 SkDebugf("\nSignal %d:\n", sig); |
| 24 while (unw_step(&cursor) > 0) { | 22 while (unw_step(&cursor) > 0) { |
| 25 static const size_t kMax = 256; | 23 static const size_t kMax = 256; |
| 26 char mangled[kMax], demangled[kMax]; | 24 char mangled[kMax], demangled[kMax]; |
| 27 unw_word_t offset; | 25 unw_word_t offset; |
| 28 unw_get_proc_name(&cursor, mangled, kMax, &offset); | 26 unw_get_proc_name(&cursor, mangled, kMax, &offset); |
| 29 | 27 |
| 30 int ok; | 28 int ok; |
| 31 size_t len = kMax; | 29 size_t len = kMax; |
| 32 abi::__cxa_demangle(mangled, demangled, &len, &ok); | 30 abi::__cxa_demangle(mangled, demangled, &len, &ok); |
| 33 | 31 |
| 34 fprintf(stderr, "%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t) offset); | 32 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset) ; |
| 35 } | 33 } |
| 36 fprintf(stderr, "\n"); | 34 SkDebugf("\n"); |
| 37 | 35 |
| 38 // Exit NOW. Don't notify other threads, don't call anything registered wit h atexit(). | 36 // Exit NOW. Don't notify other threads, don't call anything registered wit h atexit(). |
| 39 _Exit(sig); | 37 _exit(sig); |
| 40 } | 38 } |
| 41 | 39 |
| 42 #elif defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_NACL) // NACL doesn' t have backtrace(). | 40 #elif defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_NACL) // NACL doesn' t have backtrace(). |
| 43 | 41 |
| 44 // We'd use libunwind here too, but it's a pain to get installed for both 32 and 64 bit on bots. | 42 // We'd use libunwind here too, but it's a pain to get installed for both 32 and 64 bit on bots. |
| 45 // Doesn't matter much: catchsegv is best anyway. | 43 // Doesn't matter much: catchsegv is best anyway. |
| 46 #include <execinfo.h> | 44 #include <execinfo.h> |
| 47 | 45 |
| 48 static void handler(int sig) { | 46 static void handler(int sig) { |
| 49 static const int kMax = 64; | 47 static const int kMax = 64; |
| 50 void* stack[kMax]; | 48 void* stack[kMax]; |
| 51 const int count = backtrace(stack, kMax); | 49 const int count = backtrace(stack, kMax); |
| 52 | 50 |
| 53 fprintf(stderr, "\nSignal %d:\n", sig); | 51 SkDebugf("\nSignal %d:\n", sig); |
| 54 backtrace_symbols_fd(stack, count, 2/*stderr*/); | 52 backtrace_symbols_fd(stack, count, 2/*stderr*/); |
| 55 | 53 |
| 56 // Exit NOW. Don't notify other threads, don't call anything registered wit h atexit(). | 54 // Exit NOW. Don't notify other threads, don't call anything registered wit h atexit(). |
| 57 _Exit(sig); | 55 _exit(sig); |
| 58 } | 56 } |
| 59 | 57 |
| 60 #endif | 58 #endif |
| 61 | 59 |
| 62 #if defined(SK_BUILD_FOR_MAC) || (defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUIL D_FOR_NACL)) | 60 #if defined(SK_BUILD_FOR_MAC) || (defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUIL D_FOR_NACL)) |
| 61 #include <signal.h> | |
| 63 | 62 |
| 64 void SetupCrashHandler() { | 63 void SetupCrashHandler() { |
| 65 static const int kSignals[] = { | 64 static const int kSignals[] = { |
| 66 SIGABRT, | 65 SIGABRT, |
| 67 SIGBUS, | 66 SIGBUS, |
| 68 SIGFPE, | 67 SIGFPE, |
| 69 SIGILL, | 68 SIGILL, |
| 70 SIGSEGV, | 69 SIGSEGV, |
| 71 }; | 70 }; |
| 72 | 71 |
| 73 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) { | 72 for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) { |
| 74 // Register our signal handler unless something's already done so (e.g. catchsegv). | 73 // Register our signal handler unless something's already done so (e.g. catchsegv). |
| 75 void (*prev)(int) = signal(kSignals[i], handler); | 74 void (*prev)(int) = signal(kSignals[i], handler); |
| 76 if (prev != SIG_DFL) { | 75 if (prev != SIG_DFL) { |
| 77 signal(kSignals[i], prev); | 76 signal(kSignals[i], prev); |
| 78 } | 77 } |
| 79 } | 78 } |
| 80 } | 79 } |
| 81 | 80 |
| 82 // TODO: #elif defined(SK_BUILD_FOR_WIN) when I find a Windows machine to work f rom. | 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 CONTEXT* c = e->ContextRecord; | |
| 109 | |
| 110 HANDLE hProcess = GetCurrentProcess(); | |
| 111 SymInitialize(hProcess, 0, true); | |
| 112 STACKFRAME64 frame; | |
| 113 sk_bzero(&frame, sizeof(frame)); | |
| 114 | |
| 115 frame.AddrPC.Offset = c->Eip; | |
|
bungeman-skia
2014/06/18 22:28:28
CONTEXT is a completely different struct on x86 an
| |
| 116 frame.AddrPC.Mode = AddrModeFlat; | |
| 117 frame.AddrStack.Offset = c->Esp; | |
| 118 frame.AddrStack.Mode = AddrModeFlat; | |
| 119 frame.AddrFrame.Offset = c->Ebp; | |
| 120 frame.AddrFrame.Mode = AddrModeFlat; | |
| 121 | |
| 122 while (StackWalk64(sizeof(void*) == 4 ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE _MACHINE_AMD64, | |
|
bungeman-skia
2014/06/18 22:28:28
Because it's what we're actually after here, we sh
| |
| 123 GetCurrentProcess(), | |
| 124 GetCurrentThread(), | |
| 125 &frame, | |
| 126 c, | |
| 127 NULL, | |
| 128 SymFunctionTableAccess64, | |
| 129 SymGetModuleBase64, | |
| 130 NULL)) { | |
| 131 DWORD64 offset; | |
| 132 static const int kMaxNameLength = 1024; | |
| 133 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength]; | |
| 134 sk_bzero(buffer, sizeof(buffer)); | |
| 135 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer ); | |
| 136 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); | |
| 137 symbol->MaxNameLength = kMaxNameLength - 1; | |
| 138 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol); | |
| 139 SkDebugf("%s +%x\n", symbol->Name, offset); | |
| 140 } | |
| 141 | |
| 142 // Exit NOW. Don't notify other threads, don't call anything registered wit h atexit(). | |
| 143 _exit(1); | |
| 144 | |
| 145 // The compiler wants us to return something. This is what we'd do if we di dn't _exit(). | |
| 146 return EXCEPTION_EXECUTE_HANDLER; | |
| 147 } | |
| 148 | |
| 149 void SetupCrashHandler() { | |
| 150 SetUnhandledExceptionFilter(handler); | |
| 151 } | |
| 83 | 152 |
| 84 #else | 153 #else |
| 85 | 154 |
| 86 void SetupCrashHandler() { } | 155 void SetupCrashHandler() { } |
| 87 | 156 |
| 88 #endif | 157 #endif |
| OLD | NEW |