| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- #include "port/stack_trace.h"
- #if defined(ROCKSDB_LITE) || !(defined(ROCKSDB_BACKTRACE) || defined(OS_MACOSX)) || \
- defined(CYGWIN) || defined(OS_FREEBSD) || defined(OS_SOLARIS)
- // noop
- namespace ROCKSDB_NAMESPACE {
- namespace port {
- void InstallStackTraceHandler() {}
- void PrintStack(int /*first_frames_to_skip*/) {}
- } // namespace port
- } // namespace ROCKSDB_NAMESPACE
- #else
- #include <execinfo.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <cxxabi.h>
- namespace ROCKSDB_NAMESPACE {
- namespace port {
- namespace {
- #if defined(OS_LINUX) || defined(OS_FREEBSD)
- const char* GetExecutableName() {
- static char name[1024];
- char link[1024];
- snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
- auto read = readlink(link, name, sizeof(name) - 1);
- if (-1 == read) {
- return nullptr;
- } else {
- name[read] = 0;
- return name;
- }
- }
- 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 defined(OS_MACOSX)
- void PrintStackTraceLine(const char* symbol, void* frame) {
- static int pid = getpid();
- // out source to atos, for the address translation
- const int kLineMax = 256;
- char cmd[kLineMax];
- snprintf(cmd, kLineMax, "xcrun atos %p -p %d 2>&1", frame, pid);
- 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 if (symbol) {
- fprintf(stderr, "%s ", symbol);
- }
- fprintf(stderr, "\n");
- }
- #endif
- } // namespace
- void PrintStack(int first_frames_to_skip) {
- const int kMaxFrames = 100;
- void* frames[kMaxFrames];
- auto num_frames = backtrace(frames, kMaxFrames);
- auto symbols = backtrace_symbols(frames, num_frames);
- for (int i = first_frames_to_skip; i < num_frames; ++i) {
- fprintf(stderr, "#%-2d ", i - first_frames_to_skip);
- PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]);
- }
- free(symbols);
- }
- 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);
- }
- void InstallStackTraceHandler() {
- // just use the plain old signal as it's simple and sufficient
- // for this use case
- signal(SIGILL, StackTraceHandler);
- signal(SIGSEGV, StackTraceHandler);
- signal(SIGBUS, StackTraceHandler);
- signal(SIGABRT, StackTraceHandler);
- }
- } // namespace port
- } // namespace ROCKSDB_NAMESPACE
- #endif
|