stack_trace.cc 3.5 KB
Newer Older
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
S
Siying Dong 已提交
2 3 4
//  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).
5
//
I
Igor Canadi 已提交
6
#include "port/stack_trace.h"
7

D
dx9 已提交
8
#if defined(ROCKSDB_LITE) || !(defined(ROCKSDB_BACKTRACE) || defined(OS_MACOSX)) || \
T
Tomas Kolda 已提交
9
    defined(CYGWIN) || defined(OS_FREEBSD) || defined(OS_SOLARIS)
I
Igor Canadi 已提交
10 11 12

// noop

I
Igor Canadi 已提交
13 14
namespace rocksdb {
namespace port {
I
Igor Canadi 已提交
15
void InstallStackTraceHandler() {}
A
Andrew Kryczka 已提交
16
void PrintStack(int /*first_frames_to_skip*/) {}
I
Igor Canadi 已提交
17 18
}  // namespace port
}  // namespace rocksdb
I
Igor Canadi 已提交
19 20

#else
21 22 23 24 25 26 27

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
28
#include <cxxabi.h>
29

I
Igor Canadi 已提交
30 31 32
namespace rocksdb {
namespace port {

I
Igor Canadi 已提交
33
namespace {
34

35
#if defined(OS_LINUX) || defined(OS_FREEBSD)
I
Igor Canadi 已提交
36
const char* GetExecutableName() {
37 38 39 40
  static char name[1024];

  char link[1024];
  snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
41
  auto read = readlink(link, name, sizeof(name) - 1);
42 43 44 45 46 47 48 49
  if (-1 == read) {
    return nullptr;
  } else {
    name[read] = 0;
    return name;
  }
}

I
Igor Canadi 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
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");
}
75
#elif defined(OS_MACOSX)
I
Igor Canadi 已提交
76 77

void PrintStackTraceLine(const char* symbol, void* frame) {
I
Igor Canadi 已提交
78 79 80 81
  static int pid = getpid();
  // out source to atos, for the address translation
  const int kLineMax = 256;
  char cmd[kLineMax];
I
Igor Canadi 已提交
82
  snprintf(cmd, kLineMax, "xcrun atos %p -p %d  2>&1", frame, pid);
I
Igor Canadi 已提交
83 84 85 86 87 88
  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);
89
    }
I
Igor Canadi 已提交
90 91 92
    pclose(f);
  } else if (symbol) {
    fprintf(stderr, "%s ", symbol);
I
Igor Canadi 已提交
93
  }
I
Igor Canadi 已提交
94

I
Igor Canadi 已提交
95 96 97 98 99 100 101
  fprintf(stderr, "\n");
}

#endif

}  // namespace

102
void PrintStack(int first_frames_to_skip) {
103
  const int kMaxFrames = 100;
I
Igor Canadi 已提交
104
  void* frames[kMaxFrames];
105 106 107 108

  auto num_frames = backtrace(frames, kMaxFrames);
  auto symbols = backtrace_symbols(frames, num_frames);

109 110
  for (int i = first_frames_to_skip; i < num_frames; ++i) {
    fprintf(stderr, "#%-2d  ", i - first_frames_to_skip);
I
Igor Canadi 已提交
111
    PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]);
112
  }
113
  free(symbols);
114
}
115

116 117 118 119 120 121
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);
122 123 124 125 126 127 128 129 130 131 132 133 134
  // 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);
}

I
Igor Canadi 已提交
135 136
}  // namespace port
}  // namespace rocksdb
I
Igor Canadi 已提交
137 138

#endif