From 9644e0e0c7892dcbf4c27a34890a74097be3a17a Mon Sep 17 00:00:00 2001 From: Igor Canadi Date: Fri, 6 Dec 2013 17:11:09 -0800 Subject: [PATCH] Print stack trace on assertion failure Summary: This will help me a lot! When we hit an assertion in unittest, we get the whole stack trace now. Also, changed stack trace a bit, we now include actual demangled C++ class::function symbols! Test Plan: Added ASSERT_TRUE(false) to a test, observed a stack trace Reviewers: haobo, dhruba, kailiu Reviewed By: kailiu CC: leveldb Differential Revision: https://reviews.facebook.net/D14499 --- port/stack_trace.cc | 32 ++++++++++++++++---------------- util/stack_trace.h | 3 +++ util/testharness.h | 2 ++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/port/stack_trace.cc b/port/stack_trace.cc index a98f26eac..aa01fd0cf 100644 --- a/port/stack_trace.cc +++ b/port/stack_trace.cc @@ -31,12 +31,7 @@ static const char* GetExecutableName() } } -static void StackTraceHandler(int sig) { - // reset to default handler - signal(sig, SIG_DFL); - - fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig)); - +void PrintStack(int first_frames_to_skip) { const int kMaxFrames = 100; void *frames[kMaxFrames]; @@ -45,11 +40,8 @@ static void StackTraceHandler(int sig) { auto executable = GetExecutableName(); - const int kSkip = 2; // skip the top two signal handler related frames - - for (int i = kSkip; i < num_frames; ++i) - { - fprintf(stderr, "#%-2d %p ", i - kSkip, frames[i]); + for (int i = first_frames_to_skip; i < num_frames; ++i) { + fprintf(stderr, "#%-2d ", i - first_frames_to_skip); if (symbols) { fprintf(stderr, "%s ", symbols[i]); } @@ -57,22 +49,29 @@ static void StackTraceHandler(int sig) { // out source to addr2line, for the address translation const int kLineMax = 256; char cmd[kLineMax]; - sprintf(cmd,"addr2line %p -e %s 2>&1", frames[i] , executable); + sprintf(cmd, "addr2line %p -e %s -f -C 2>&1", frames[i], executable); auto f = popen(cmd, "r"); if (f) { char line[kLineMax]; while (fgets(line, sizeof(line), f)) { - fprintf(stderr, "%s", line); + line[strlen(line) - 1] = 0; // remove newline + fprintf(stderr, "%s\t", line); } pclose(f); - } else { - fprintf(stderr, "\n"); } } else { - fprintf(stderr, "\n"); + fprintf(stderr, " %p", frames[i]); } + fprintf(stderr, "\n"); } +} +static void StackTraceHandler(int sig) { + // reset to default handler + signal(sig, SIG_DFL); + fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig)); + // skip the top three signal handler related frames + PrintStack(3); // re-signal to default handler (so we still get core dump if needed...) raise(sig); } @@ -96,6 +95,7 @@ void InstallStackTraceHandler() { namespace rocksdb { void InstallStackTraceHandler() {} +void PrintStack(int first_frames_to_skip) {} } diff --git a/util/stack_trace.h b/util/stack_trace.h index 888304462..3b06e1df0 100644 --- a/util/stack_trace.h +++ b/util/stack_trace.h @@ -11,4 +11,7 @@ namespace rocksdb { // Currently supports linux only. No-op otherwise. void InstallStackTraceHandler(); +// Prints stack, skips skip_first_frames frames +void PrintStack(int first_frames_to_skip = 0); + } // namespace rocksdb diff --git a/util/testharness.h b/util/testharness.h index 936ee8b6c..f15917816 100644 --- a/util/testharness.h +++ b/util/testharness.h @@ -15,6 +15,7 @@ #include "rocksdb/env.h" #include "rocksdb/slice.h" #include "util/random.h" +#include "util/stack_trace.h" namespace rocksdb { namespace test { @@ -58,6 +59,7 @@ class Tester { ~Tester() { if (!ok_) { fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); + PrintStack(2); exit(1); } }