summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/skia/tools/CrashHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/skia/tools/CrashHandler.cpp')
-rw-r--r--chromium/third_party/skia/tools/CrashHandler.cpp172
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