aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2014-06-19 07:41:58 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-06-19 07:41:59 -0700
commit3f73e8c8d589e0d5a1f75327b4aa22c1e745732d (patch)
tree0b7a8e78028cffe7048ba9dfc19addccb50c89e8
parent373dd9b52f88158edd1e24419e6d937efaf59d55 (diff)
CrashHandler for Windows.
Plus, print out assertion failures on Windows, and some little tweaks to CrashHandler on other platforms for consistency. BUG=skia: R=bungeman@google.com, mtklein@google.com, reed@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/340523007
-rw-r--r--gyp/crash_handler.gyp7
-rw-r--r--include/core/SkPostConfig.h36
-rw-r--r--tools/CrashHandler.cpp98
3 files changed, 117 insertions, 24 deletions
diff --git a/gyp/crash_handler.gyp b/gyp/crash_handler.gyp
index aa5ad94720..7e3599c8d9 100644
--- a/gyp/crash_handler.gyp
+++ b/gyp/crash_handler.gyp
@@ -7,5 +7,12 @@
'direct_dependent_settings': {
'include_dirs': [ '../tools' ],
},
+ 'all_dependent_settings': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [ 'Dbghelp.lib' ],
+ }
+ },
+ }
}]
}
diff --git a/include/core/SkPostConfig.h b/include/core/SkPostConfig.h
index 6e54bfd8b3..d513d20633 100644
--- a/include/core/SkPostConfig.h
+++ b/include/core/SkPostConfig.h
@@ -107,10 +107,14 @@
#endif
#ifndef SK_CRASH
-# if 1 // set to 0 for infinite loop, which can help connecting gdb
-# define SK_CRASH() do { SkNO_RETURN_HINT(); *(int *)(uintptr_t)0xbbadbeef = 0; } while (false)
+# ifdef SK_BUILD_FOR_WIN
+# define SK_CRASH() __debugbreak()
# else
-# define SK_CRASH() do { SkNO_RETURN_HINT(); } while (true)
+# if 1 // set to 0 for infinite loop, which can help connecting gdb
+# define SK_CRASH() do { SkNO_RETURN_HINT(); *(int *)(uintptr_t)0xbbadbeef = 0; } while (false)
+# else
+# define SK_CRASH() do { SkNO_RETURN_HINT(); } while (true)
+# endif
# endif
#endif
@@ -154,10 +158,6 @@
# undef NOMINMAX
# endif
#
-# ifndef SK_ALWAYSBREAK
-# define SK_ALWAYSBREAK(p) do { if (!(p)) { SkNO_RETURN_HINT(); __debugbreak(); }} while (false)
-# endif
-#
# ifndef SK_A32_SHIFT
# define SK_A32_SHIFT 24
# define SK_R32_SHIFT 16
@@ -165,16 +165,18 @@
# define SK_B32_SHIFT 0
# endif
#
-#else
-# ifndef SK_ALWAYSBREAK
-# ifdef SK_DEBUG
-# include <stdio.h>
-# define SK_ALWAYSBREAK(cond) do { if (cond) break; \
- SkDebugf("%s:%d: failed assertion \"%s\"\n", \
- __FILE__, __LINE__, #cond); SK_CRASH(); } while (false)
-# else
-# define SK_ALWAYSBREAK(cond) do { if (cond) break; SK_CRASH(); } while (false)
-# endif
+#endif
+
+#ifndef SK_ALWAYSBREAK
+# ifdef SK_DEBUG
+# define SK_ALWAYSBREAK(cond) do { \
+ if (cond) break; \
+ SkNO_RETURN_HINT(); \
+ SkDebugf("%s:%d: failed assertion \"%s\"\n", __FILE__, __LINE__, #cond); \
+ SK_CRASH(); \
+ } while (false)
+# else
+# define SK_ALWAYSBREAK(cond) do { if (cond) break; SK_CRASH(); } while (false)
# endif
#endif
diff --git a/tools/CrashHandler.cpp b/tools/CrashHandler.cpp
index cd104a6859..ffd9f3bedb 100644
--- a/tools/CrashHandler.cpp
+++ b/tools/CrashHandler.cpp
@@ -2,9 +2,7 @@
#include "SkTypes.h"
-#include <stdio.h>
#include <stdlib.h>
-#include <signal.h>
#if defined(SK_BUILD_FOR_MAC)
@@ -20,7 +18,7 @@ static void handler(int sig) {
unw_cursor_t cursor;
unw_init_local(&cursor, &context);
- fprintf(stderr, "\nSignal %d:\n", sig);
+ SkDebugf("\nSignal %d:\n", sig);
while (unw_step(&cursor) > 0) {
static const size_t kMax = 256;
char mangled[kMax], demangled[kMax];
@@ -31,9 +29,9 @@ static void handler(int sig) {
size_t len = kMax;
abi::__cxa_demangle(mangled, demangled, &len, &ok);
- fprintf(stderr, "%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
+ SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
}
- fprintf(stderr, "\n");
+ SkDebugf("\n");
// Exit NOW. Don't notify other threads, don't call anything registered with atexit().
_Exit(sig);
@@ -50,7 +48,7 @@ static void handler(int sig) {
void* stack[kMax];
const int count = backtrace(stack, kMax);
- fprintf(stderr, "\nSignal %d:\n", sig);
+ 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().
@@ -60,6 +58,7 @@ static void handler(int 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[] = {
@@ -79,7 +78,92 @@ void SetupCrashHandler() {
}
}
-// TODO: #elif defined(SK_BUILD_FOR_WIN) when I find a Windows machine to work from.
+#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