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
This commit is contained in:
Igor Canadi 2014-04-23 09:11:35 -04:00
parent a570740727
commit f9f8965e96
6 changed files with 70 additions and 48 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@ build_config.mk
*.jar
*.*jnilib*
*.d-e
*.o-*
ldb
manifest_dump

View File

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

View File

@ -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 <execinfo.h>
#include <signal.h>
@ -14,10 +24,10 @@
#include <string.h>
#include <unistd.h>
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

View File

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

View File

@ -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 <assert.h>
namespace {
@ -26,7 +26,7 @@ void f3() {
} // namespace
int main() {
rocksdb::InstallStackTraceHandler();
rocksdb::port::InstallStackTraceHandler();
f3();

View File

@ -12,10 +12,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#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);
}
}