stack_trace.cc 3.4 KB
Newer Older
1 2 3 4 5
//  Copyright (c) 2013, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  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.
//
I
Igor Canadi 已提交
6
#include "port/stack_trace.h"
7

S
sdong 已提交
8 9
#if defined(ROCKSDB_LITE) || !(defined(OS_LINUX) || defined(OS_MACOSX)) || \
    defined(CYGWIN)
I
Igor Canadi 已提交
10 11 12

// noop

I
Igor Canadi 已提交
13 14
namespace rocksdb {
namespace port {
I
Igor Canadi 已提交
15 16
void InstallStackTraceHandler() {}
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

I
Igor Canadi 已提交
35 36
#ifdef OS_LINUX
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
}
114

115 116 117 118 119 120
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);
121 122 123 124 125 126 127 128 129 130 131 132 133
  // 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 已提交
134 135
}  // namespace port
}  // namespace rocksdb
I
Igor Canadi 已提交
136 137

#endif