dump stack trace in FM on failure
In CrashHandler...
- make CrashHandler a non-noop... don't know why it's disabled
- fix bitrot since we last built it
- update to demangle symbols on Linux too, not just Mac
- catch SIGTRAP, which will catch SK_ABORT / SkASSERT,
unless otherwise hooked (e.g. by a debugger)
In fm...
- use CrashHandler
- convert exit_with_failure to SK_ABORT so they'll also dump a trace
- flush stdout after printing what's running
Change-Id: Ib20d0e4f442d73c28e193396dc6e85935fc58544
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/208151
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 9faf14d..61715a7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1654,7 +1654,10 @@
if (is_ios) {
sources += [ "tools/ios_utils.m" ]
libs += [ "Foundation.framework" ]
+ } else if (is_win) {
+ libs += [ "DbgHelp.lib" ]
}
+
defines = []
if (skia_tools_require_resources) {
defines += [ "SK_TOOLS_REQUIRE_RESOURCES" ]
diff --git a/tools/CrashHandler.cpp b/tools/CrashHandler.cpp
index 5fa6a10..fa322e3 100644
--- a/tools/CrashHandler.cpp
+++ b/tools/CrashHandler.cpp
@@ -11,18 +11,13 @@
#include <stdlib.h>
-// Disable SetupCrashHandler() unless SK_CRASH_HANDLER is defined.
-#ifndef SK_CRASH_HANDLER
- void SetupCrashHandler() { }
-
-#elif defined(SK_BUILD_FOR_GOOGLE3)
+#if defined(SK_BUILD_FOR_GOOGLE3)
#include "base/process_state.h"
void SetupCrashHandler() { InstallSignalHandlers(); }
#else
#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>
@@ -55,18 +50,34 @@
}
#elif defined(SK_BUILD_FOR_UNIX)
-
// 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 <cxxabi.h>
+ #include <dlfcn.h>
#include <execinfo.h>
+ #include <string.h>
static void handler(int sig) {
- static const int kMax = 64;
- void* stack[kMax];
- const int count = backtrace(stack, kMax);
+ void* stack[64];
+ const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
+ char** symbols = backtrace_symbols(stack, count);
SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
- backtrace_symbols_fd(stack, count, 2/*stderr*/);
+ for (int i = 0; i < count; i++) {
+ Dl_info info;
+ if (dladdr(stack[i], &info) && info.dli_sname) {
+ char demangled[256];
+ size_t len = SK_ARRAY_COUNT(demangled);
+ int ok;
+
+ abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
+ if (ok == 0) {
+ SkDebugf(" %s\n", demangled);
+ continue;
+ }
+ }
+ SkDebugf(" %s\n", symbols[i]);
+ }
// Exit NOW. Don't notify other threads, don't call anything registered with atexit().
_Exit(sig);
@@ -84,6 +95,7 @@
SIGFPE,
SIGILL,
SIGSEGV,
+ SIGTRAP,
};
for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
@@ -95,9 +107,10 @@
}
}
- #elif defined(SK_CRASH_HANDLER) && defined(SK_BUILD_FOR_WIN)
+ #elif defined(SK_BUILD_FOR_WIN)
#include <DbgHelp.h>
+ #include "SkMalloc.h"
static const struct {
const char* name;
@@ -184,9 +197,9 @@
SetUnhandledExceptionFilter(handler);
}
- #else // We asked for SK_CRASH_HANDLER, but it's not Mac, Linux, or Windows. Sorry!
+ #else
void SetupCrashHandler() { }
#endif
-#endif // SK_CRASH_HANDLER
+#endif // SK_BUILD_FOR_GOOGLE3?
diff --git a/tools/fm/fm.cpp b/tools/fm/fm.cpp
index 2a918ab..67e2e6e 100644
--- a/tools/fm/fm.cpp
+++ b/tools/fm/fm.cpp
@@ -3,6 +3,7 @@
#include "CommandLineFlags.h"
#include "CommonFlags.h"
+#include "CrashHandler.h"
#include "EventTracingPriv.h"
#include "GrContextFactory.h"
#include "GrContextOptions.h"
@@ -96,11 +97,6 @@
return false;
}
-static void exit_with_failure() {
- // TODO: dump stack trace, debug trap, print currently running job, etc?
- exit(1);
-}
-
struct Result {
enum { Ok, Skip, Fail} status;
SkString failure;
@@ -350,6 +346,7 @@
int main(int argc, char** argv) {
CommandLineFlags::Parse(argc, argv);
+ SetupCrashHandler();
if (FLAGS_cpuDetect) {
SkGraphics::Init();
@@ -503,6 +500,7 @@
for (auto source : sources) {
const auto start = std::chrono::steady_clock::now();
fprintf(stdout, "%50s", source.name.c_str());
+ fflush(stdout);
const SkImageInfo info = unsized_info.makeWH(source.size.width(),
source.size.height());
@@ -513,8 +511,7 @@
case Result::Ok: break;
case Result::Skip: return false;
case Result::Fail:
- fprintf(stderr, "%s failed: %s\n", source.name.c_str(), result.failure.c_str());
- exit_with_failure();
+ SK_ABORT(result.failure.c_str());
}
return true;
};
@@ -550,8 +547,7 @@
SkBitmap bitmap;
if (image && !image->asLegacyBitmap(&bitmap)) {
- fprintf(stderr, "SkImage::asLegacyBitmap() failed.\n");
- exit_with_failure();
+ SK_ABORT("SkImage::asLegacyBitmap() failed.");
}
HashAndEncode hashAndEncode{bitmap};
@@ -577,8 +573,7 @@
if (image) {
if (!hashAndEncode.writePngTo(path.c_str(), md5.c_str(),
FLAGS_key, FLAGS_properties)) {
- fprintf(stderr, "Could not write to %s.\n", path.c_str());
- exit_with_failure();
+ SK_ABORT("Could not write .png.");
}
} else {
SkFILEWStream file(path.c_str());