From f9f8965e96463e0240ff509639e4e8118ba9225b Mon Sep 17 00:00:00 2001 From: Igor Canadi Date: Wed, 23 Apr 2014 09:11:35 -0400 Subject: [PATCH] Print out stack trace in mac, too Summary: While debugging Mac-only issue with ThreadLocalPtr, this was very useful. Let's print out stack trace in MAC OS, too. Test Plan: Verified that somewhat useful stack trace was generated on mac. Will run PrintStack() on linux, too. Reviewers: ljin, haobo Reviewed By: haobo CC: leveldb Differential Revision: https://reviews.facebook.net/D18189 --- .gitignore | 1 + db/db_bench.cc | 4 +- port/stack_trace.cc | 101 +++++++++++++++++++++-------------- {util => port}/stack_trace.h | 4 +- util/signal_test.cc | 4 +- util/testharness.h | 4 +- 6 files changed, 70 insertions(+), 48 deletions(-) rename {util => port}/stack_trace.h (90%) diff --git a/.gitignore b/.gitignore index a3a70ee311..995046089d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ build_config.mk *.jar *.*jnilib* *.d-e +*.o-* ldb manifest_dump diff --git a/db/db_bench.cc b/db/db_bench.cc index ecf40b9436..2b52032ca2 100644 --- a/db/db_bench.cc +++ b/db/db_bench.cc @@ -28,11 +28,11 @@ #include "rocksdb/statistics.h" #include "rocksdb/perf_context.h" #include "port/port.h" +#include "port/stack_trace.h" #include "util/crc32c.h" #include "util/histogram.h" #include "util/mutexlock.h" #include "util/random.h" -#include "util/stack_trace.h" #include "util/string_util.h" #include "util/statistics.h" #include "util/testutil.h" @@ -2528,7 +2528,7 @@ class Benchmark { } // namespace rocksdb int main(int argc, char** argv) { - rocksdb::InstallStackTraceHandler(); + rocksdb::port::InstallStackTraceHandler(); google::SetUsageMessage(std::string("\nUSAGE:\n") + std::string(argv[0]) + " [OPTIONS]..."); google::ParseCommandLineFlags(&argc, &argv, true); diff --git a/port/stack_trace.cc b/port/stack_trace.cc index aa01fd0cf3..9222ba438b 100644 --- a/port/stack_trace.cc +++ b/port/stack_trace.cc @@ -3,9 +3,19 @@ // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. // -#include "util/stack_trace.h" +#include "port/stack_trace.h" -#ifdef OS_LINUX +namespace rocksdb { +namespace port { + +#if defined(ROCKSDB_LITE) || !(defined(OS_LINUX) || defined(OS_MACOSX)) + +// noop + +void InstallStackTraceHandler() {} +void PrintStack(int first_frames_to_skip) {} + +#else #include #include @@ -14,10 +24,10 @@ #include #include -namespace rocksdb { +namespace { -static const char* GetExecutableName() -{ +#ifdef OS_LINUX +const char* GetExecutableName() { static char name[1024]; char link[1024]; @@ -31,38 +41,56 @@ static const char* GetExecutableName() } } +void PrintStackTraceLine(const char* symbol, void* frame) { + static const char* executable = GetExecutableName(); + if (symbol) { + fprintf(stderr, "%s ", symbol); + } + if (executable) { + // out source to addr2line, for the address translation + const int kLineMax = 256; + char cmd[kLineMax]; + snprintf(cmd, kLineMax, "addr2line %p -e %s -f -C 2>&1", frame, executable); + auto f = popen(cmd, "r"); + if (f) { + char line[kLineMax]; + while (fgets(line, sizeof(line), f)) { + line[strlen(line) - 1] = 0; // remove newline + fprintf(stderr, "%s\t", line); + } + pclose(f); + } + } else { + fprintf(stderr, " %p", frame); + } + + fprintf(stderr, "\n"); +} +#elif OS_MACOSX + +void PrintStackTraceLine(const char* symbol, void* frame) { + // TODO(icanadi) demangle + if (symbol) { + fprintf(stderr, "%s ", symbol); + } + fprintf(stderr, " %p", frame); + fprintf(stderr, "\n"); +} + +#endif + +} // namespace + void PrintStack(int first_frames_to_skip) { const int kMaxFrames = 100; - void *frames[kMaxFrames]; + void* frames[kMaxFrames]; auto num_frames = backtrace(frames, kMaxFrames); auto symbols = backtrace_symbols(frames, num_frames); - auto executable = GetExecutableName(); - 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]); - } - if (executable) { - // out source to addr2line, for the address translation - const int kLineMax = 256; - char cmd[kLineMax]; - 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)) { - line[strlen(line) - 1] = 0; // remove newline - fprintf(stderr, "%s\t", line); - } - pclose(f); - } - } else { - fprintf(stderr, " %p", frames[i]); - } - fprintf(stderr, "\n"); + PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]); } } @@ -85,18 +113,9 @@ void InstallStackTraceHandler() { signal(SIGABRT, StackTraceHandler); printf("Installed stack trace handler for SIGILL SIGSEGV SIGBUS SIGABRT\n"); - } -} // namespace rocksdb +#endif -#else // no-op for non-linux system for now - -namespace rocksdb { - -void InstallStackTraceHandler() {} -void PrintStack(int first_frames_to_skip) {} - -} - -#endif // OS_LINUX +} // namespace port +} // namespace rocksdb diff --git a/util/stack_trace.h b/port/stack_trace.h similarity index 90% rename from util/stack_trace.h rename to port/stack_trace.h index 3b06e1df06..8bc6c7d2ec 100644 --- a/util/stack_trace.h +++ b/port/stack_trace.h @@ -5,6 +5,7 @@ // #pragma once namespace rocksdb { +namespace port { // Install a signal handler to print callstack on the following signals: // SIGILL SIGSEGV SIGBUS SIGABRT @@ -14,4 +15,5 @@ void InstallStackTraceHandler(); // Prints stack, skips skip_first_frames frames void PrintStack(int first_frames_to_skip = 0); -} // namespace rocksdb +} // namespace port +} // namespace rocksdb diff --git a/util/signal_test.cc b/util/signal_test.cc index d3446818d8..f51fa548ef 100644 --- a/util/signal_test.cc +++ b/util/signal_test.cc @@ -3,7 +3,7 @@ // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. // -#include "util/stack_trace.h" +#include "port/stack_trace.h" #include namespace { @@ -26,7 +26,7 @@ void f3() { } // namespace int main() { - rocksdb::InstallStackTraceHandler(); + rocksdb::port::InstallStackTraceHandler(); f3(); diff --git a/util/testharness.h b/util/testharness.h index f15917816e..52c29848d9 100644 --- a/util/testharness.h +++ b/util/testharness.h @@ -12,10 +12,10 @@ #include #include #include +#include "port/stack_trace.h" #include "rocksdb/env.h" #include "rocksdb/slice.h" #include "util/random.h" -#include "util/stack_trace.h" namespace rocksdb { namespace test { @@ -59,7 +59,7 @@ class Tester { ~Tester() { if (!ok_) { fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); - PrintStack(2); + port::PrintStack(2); exit(1); } }