diff options
Diffstat (limited to 'chromium/third_party/skia/tools/CrashHandler.cpp')
-rw-r--r-- | chromium/third_party/skia/tools/CrashHandler.cpp | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/chromium/third_party/skia/tools/CrashHandler.cpp b/chromium/third_party/skia/tools/CrashHandler.cpp new file mode 100644 index 00000000000..ffd9f3bedb0 --- /dev/null +++ b/chromium/third_party/skia/tools/CrashHandler.cpp @@ -0,0 +1,172 @@ +#include "CrashHandler.h" + +#include "SkTypes.h" + +#include <stdlib.h> + +#if defined(SK_BUILD_FOR_MAC) + +// We only use local unwinding, so we can define this to select a faster implementation. +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <cxxabi.h> + +static void handler(int sig) { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + SkDebugf("\nSignal %d:\n", sig); + while (unw_step(&cursor) > 0) { + static const size_t kMax = 256; + char mangled[kMax], demangled[kMax]; + unw_word_t offset; + unw_get_proc_name(&cursor, mangled, kMax, &offset); + + int ok; + size_t len = kMax; + abi::__cxa_demangle(mangled, demangled, &len, &ok); + + SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset); + } + SkDebugf("\n"); + + // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). + _Exit(sig); +} + +#elif defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_NACL) // NACL doesn't have backtrace(). + +// We'd use libunwind here too, but it's a pain to get installed for both 32 and 64 bit on bots. +// Doesn't matter much: catchsegv is best anyway. +#include <execinfo.h> + +static void handler(int sig) { + static const int kMax = 64; + void* stack[kMax]; + const int count = backtrace(stack, kMax); + + SkDebugf("\nSignal %d:\n", sig); + backtrace_symbols_fd(stack, count, 2/*stderr*/); + + // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). + _Exit(sig); +} + +#endif + +#if defined(SK_BUILD_FOR_MAC) || (defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_NACL)) +#include <signal.h> + +void SetupCrashHandler() { + static const int kSignals[] = { + SIGABRT, + SIGBUS, + SIGFPE, + SIGILL, + SIGSEGV, + }; + + for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) { + // Register our signal handler unless something's already done so (e.g. catchsegv). + void (*prev)(int) = signal(kSignals[i], handler); + if (prev != SIG_DFL) { + signal(kSignals[i], prev); + } + } +} + +#elif defined(SK_BUILD_FOR_WIN) + +#include <DbgHelp.h> + +static const struct { + const char* name; + int code; +} kExceptions[] = { +#define _(E) {#E, E} + _(EXCEPTION_ACCESS_VIOLATION), + _(EXCEPTION_BREAKPOINT), + _(EXCEPTION_INT_DIVIDE_BY_ZERO), + _(EXCEPTION_STACK_OVERFLOW), + // TODO: more? +#undef _ +}; + +static LONG WINAPI handler(EXCEPTION_POINTERS* e) { + const DWORD code = e->ExceptionRecord->ExceptionCode; + SkDebugf("\nCaught exception %u", code); + for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) { + if (kExceptions[i].code == code) { + SkDebugf(" %s", kExceptions[i].name); + } + } + SkDebugf("\n"); + + // We need to run SymInitialize before doing any of the stack walking below. + HANDLE hProcess = GetCurrentProcess(); + SymInitialize(hProcess, 0, true); + + STACKFRAME64 frame; + sk_bzero(&frame, sizeof(frame)); + // Start frame off from the frame that triggered the exception. + CONTEXT* c = e->ContextRecord; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Mode = AddrModeFlat; +#if defined(_X86_) + frame.AddrPC.Offset = c->Eip; + frame.AddrStack.Offset = c->Esp; + frame.AddrFrame.Offset = c->Ebp; + const DWORD machineType = IMAGE_FILE_MACHINE_I386; +#elif defined(_AMD64_) + frame.AddrPC.Offset = c->Rip; + frame.AddrStack.Offset = c->Rsp; + frame.AddrFrame.Offset = c->Rbp; + const DWORD machineType = IMAGE_FILE_MACHINE_AMD64; +#endif + + while (StackWalk64(machineType, + GetCurrentProcess(), + GetCurrentThread(), + &frame, + c, + NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, + NULL)) { + // Buffer to store symbol name in. + static const int kMaxNameLength = 1024; + uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength]; + sk_bzero(buffer, sizeof(buffer)); + + // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in how much space it can use. + IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + symbol->MaxNameLength = kMaxNameLength - 1; + + // Translate the current PC into a symbol and byte offset from the symbol. + DWORD64 offset; + SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol); + + SkDebugf("%s +%x\n", symbol->Name, offset); + } + + // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). + _exit(1); + + // The compiler wants us to return something. This is what we'd do if we didn't _exit(). + return EXCEPTION_EXECUTE_HANDLER; +} + +void SetupCrashHandler() { + SetUnhandledExceptionFilter(handler); +} + +#else + +void SetupCrashHandler() { } + +#endif |