diff options
author | mtklein <mtklein@chromium.org> | 2014-06-18 11:44:15 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-06-18 11:44:18 -0700 |
commit | 30e6e2af14e84216b1c113fd7500d0822bc81daa (patch) | |
tree | 16243d88ccd219ee59df299ad1304c2f566e1051 | |
parent | f01a6c3663970ccd6e1882e76a887e0fda467b77 (diff) |
Add basic stacktrace handler using libunwind.
This means we will all have to apt-get install libunwind8-dev on Linux. Mac comes with everything we need already.
BUG=skia:
R=reed@google.com, mtklein@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/343583005
-rw-r--r-- | bench/benchmain.cpp | 2 | ||||
-rw-r--r-- | dm/DM.cpp | 2 | ||||
-rw-r--r-- | gm/gmmain.cpp | 2 | ||||
-rw-r--r-- | gyp/bench.gyp | 5 | ||||
-rw-r--r-- | gyp/crash_handler.gyp | 11 | ||||
-rw-r--r-- | gyp/dm.gyp | 7 | ||||
-rw-r--r-- | gyp/gm.gyp | 3 | ||||
-rw-r--r-- | gyp/tests.gyp | 1 | ||||
-rw-r--r-- | gyp/tools.gyp | 3 | ||||
-rw-r--r-- | tests/skia_test.cpp | 2 | ||||
-rw-r--r-- | tools/CrashHandler.cpp | 88 | ||||
-rw-r--r-- | tools/CrashHandler.h | 9 | ||||
-rw-r--r-- | tools/bench_pictures_main.cpp | 2 |
13 files changed, 130 insertions, 7 deletions
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 6e18a8ab3a..078a2e80e0 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -6,6 +6,7 @@ */ #include "BenchTimer.h" +#include "CrashHandler.h" #include "ResultsWriter.h" #include "SkBenchLogger.h" #include "SkBenchmark.h" @@ -271,6 +272,7 @@ static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) int tool_main(int argc, char** argv); int tool_main(int argc, char** argv) { + SetupCrashHandler(); SkCommandLineFlags::Parse(argc, argv); #if SK_ENABLE_INST_COUNT if (FLAGS_leaks) { @@ -9,6 +9,7 @@ #include "SkString.h" #include "Test.h" #include "gm.h" +#include "CrashHandler.h" #include "DMBenchTask.h" #include "DMCpuGMTask.h" @@ -215,6 +216,7 @@ static void append_matching_factories(Registry* head, SkTDArray<typename Registr int tool_main(int argc, char** argv); int tool_main(int argc, char** argv) { + SetupCrashHandler(); SkAutoGraphics ag; SkCommandLineFlags::Parse(argc, argv); diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index 0be3454d82..42aed548d1 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -17,6 +17,7 @@ #include "gm_error.h" #include "gm_expectations.h" #include "system_preferences.h" +#include "CrashHandler.h" #include "SkBitmap.h" #include "SkColorPriv.h" #include "SkCommandLineFlags.h" @@ -2219,6 +2220,7 @@ static bool parse_flags_jpeg_quality() { int tool_main(int argc, char** argv); int tool_main(int argc, char** argv) { + SetupCrashHandler(); SkString usage; usage.printf("Run the golden master tests.\n"); diff --git a/gyp/bench.gyp b/gyp/bench.gyp index 8c8199167f..a5e0cd6918 100644 --- a/gyp/bench.gyp +++ b/gyp/bench.gyp @@ -9,11 +9,12 @@ 'target_name': 'bench', 'type': 'executable', 'dependencies': [ - 'skia_lib.gyp:skia_lib', 'bench_timer', + 'crash_handler.gyp:CrashHandler', + 'etc1.gyp:libetc1', 'flags.gyp:flags', 'jsoncpp.gyp:jsoncpp', - 'etc1.gyp:libetc1', + 'skia_lib.gyp:skia_lib', ], 'sources': [ '../bench/ResultsWriter.cpp', diff --git a/gyp/crash_handler.gyp b/gyp/crash_handler.gyp new file mode 100644 index 0000000000..aa5ad94720 --- /dev/null +++ b/gyp/crash_handler.gyp @@ -0,0 +1,11 @@ +{ + 'targets': [{ + 'target_name': 'CrashHandler', + 'type': 'static_library', + 'sources': [ '../tools/CrashHandler.cpp' ], + 'dependencies': [ 'skia_lib.gyp:skia_lib' ], + 'direct_dependent_settings': { + 'include_dirs': [ '../tools' ], + }, + }] +} diff --git a/gyp/dm.gyp b/gyp/dm.gyp index a849e5433c..f69ffe5f4b 100644 --- a/gyp/dm.gyp +++ b/gyp/dm.gyp @@ -55,11 +55,12 @@ '../src/utils/debugger/SkObjectParser.cpp', ], 'dependencies': [ - 'skia_lib.gyp:skia_lib', + 'crash_handler.gyp:CrashHandler', + 'etc1.gyp:libetc1', 'flags.gyp:flags', - 'jsoncpp.gyp:jsoncpp', 'gputest.gyp:skgputest', - 'etc1.gyp:libetc1', + 'jsoncpp.gyp:jsoncpp', + 'skia_lib.gyp:skia_lib', ], 'conditions': [ ['skia_android_framework', { diff --git a/gyp/gm.gyp b/gyp/gm.gyp index 9b74e74669..fd8f74d621 100644 --- a/gyp/gm.gyp +++ b/gyp/gm.gyp @@ -16,8 +16,9 @@ '../tools/sk_tool_utils.cpp', ], 'dependencies': [ - 'skia_lib.gyp:skia_lib', + 'crash_handler.gyp:CrashHandler', 'jsoncpp.gyp:jsoncpp', + 'skia_lib.gyp:skia_lib', ], 'direct_dependent_settings': { 'include_dirs': [ diff --git a/gyp/tests.gyp b/gyp/tests.gyp index 9210bf60b1..80768efa35 100644 --- a/gyp/tests.gyp +++ b/gyp/tests.gyp @@ -11,6 +11,7 @@ 'pathops_unittest.gypi', 'tests.gypi', ], + 'dependencies': [ 'crash_handler.gyp:CrashHandler' ], 'sources': [ '../tests/skia_test.cpp', ], diff --git a/gyp/tools.gyp b/gyp/tools.gyp index 9e1cf05558..9cea4617e1 100644 --- a/gyp/tools.gyp +++ b/gyp/tools.gyp @@ -300,11 +300,12 @@ ], 'dependencies': [ 'bench.gyp:bench_timer', + 'crash_handler.gyp:CrashHandler', 'flags.gyp:flags', 'jsoncpp.gyp:jsoncpp', 'skia_lib.gyp:skia_lib', - 'tools.gyp:picture_utils', 'tools.gyp:picture_renderer', + 'tools.gyp:picture_utils', 'tools.gyp:timer_data', ], }, diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp index b7fbfc627b..f70a7fab62 100644 --- a/tests/skia_test.cpp +++ b/tests/skia_test.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "CrashHandler.h" #include "OverwriteLine.h" #include "SkCommandLineFlags.h" #include "SkGraphics.h" @@ -132,6 +133,7 @@ static bool should_run(const char* testName, bool isGPUTest) { int tool_main(int argc, char** argv); int tool_main(int argc, char** argv) { + SetupCrashHandler(); SkCommandLineFlags::SetUsage(""); SkCommandLineFlags::Parse(argc, argv); Test::SetResourcePath(FLAGS_resourcePath[0]); diff --git a/tools/CrashHandler.cpp b/tools/CrashHandler.cpp new file mode 100644 index 0000000000..193e1af0b2 --- /dev/null +++ b/tools/CrashHandler.cpp @@ -0,0 +1,88 @@ +#include "CrashHandler.h" + +#include "SkTypes.h" + +#include <stdio.h> +#include <stdlib.h> +#include <signal.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); + + fprintf(stderr, "\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); + + fprintf(stderr, "%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset); + } + fprintf(stderr, "\n"); + + // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). + _Exit(sig); +} + +#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 <execinfo.h> + +static void handler(int sig) { + static const int kMax = 64; + void* stack[kMax]; + const int count = backtrace(stack, kMax); + + fprintf(stderr, "\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_UNIX) || defined(SK_BUILD_FOR_MAC) + +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); + } + } +} + +// TODO: #elif defined(SK_BUILD_FOR_WIN) when I find a Windows machine to work from. + +#else + +void SetupCrashHandler() { } + +#endif diff --git a/tools/CrashHandler.h b/tools/CrashHandler.h new file mode 100644 index 0000000000..6c22c8ee70 --- /dev/null +++ b/tools/CrashHandler.h @@ -0,0 +1,9 @@ +#ifndef CrashHandler_DEFINED +#define CrashHandler_DEFINED + +// If possible (and not already done) register a handler for a stack trace when we crash. +// Currently this works on Linux and Mac, hopefully Windows soon. +// On Linux, you will get much better results than we can deliver by running "catchsegv <program>". +void SetupCrashHandler(); + +#endif//CrashHandler_DEFINED diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp index 6b76bfc8ef..c63ffff5b7 100644 --- a/tools/bench_pictures_main.cpp +++ b/tools/bench_pictures_main.cpp @@ -6,6 +6,7 @@ */ #include "BenchTimer.h" +#include "CrashHandler.h" #include "CopyTilesRenderer.h" #include "LazyDecodeBitmap.h" #include "PictureBenchmark.h" @@ -391,6 +392,7 @@ static int process_input(const char* input, int tool_main(int argc, char** argv); int tool_main(int argc, char** argv) { + SetupCrashHandler(); SkString usage; usage.printf("Time drawing .skp files.\n" "\tPossible arguments for --filter: [%s]\n\t\t[%s]", |