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
This commit is contained in:
mtklein 2014-06-18 11:44:15 -07:00 committed by Commit bot
parent f01a6c3663
commit 30e6e2af14
13 changed files with 131 additions and 8 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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");

View File

@ -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',

11
gyp/crash_handler.gyp Normal file
View File

@ -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' ],
},
}]
}

View File

@ -55,11 +55,12 @@
'../src/utils/debugger/SkObjectParser.cpp',
],
'dependencies': [
'skia_lib.gyp:skia_lib',
'flags.gyp:flags',
'jsoncpp.gyp:jsoncpp',
'gputest.gyp:skgputest',
'crash_handler.gyp:CrashHandler',
'etc1.gyp:libetc1',
'flags.gyp:flags',
'gputest.gyp:skgputest',
'jsoncpp.gyp:jsoncpp',
'skia_lib.gyp:skia_lib',
],
'conditions': [
['skia_android_framework', {

View File

@ -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': [

View File

@ -11,6 +11,7 @@
'pathops_unittest.gypi',
'tests.gypi',
],
'dependencies': [ 'crash_handler.gyp:CrashHandler' ],
'sources': [
'../tests/skia_test.cpp',
],

View File

@ -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',
],
},

View File

@ -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]);

88
tools/CrashHandler.cpp Normal file
View File

@ -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

9
tools/CrashHandler.h Normal file
View File

@ -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

View File

@ -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]",