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

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

// noop

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

#else
20 21 22 23 24 25 26

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

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

I
Igor Canadi 已提交
32
namespace {
33

I
Igor Canadi 已提交
34 35
#ifdef OS_LINUX
const char* GetExecutableName() {
36 37 38 39
  static char name[1024];

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

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

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

#endif

}  // namespace

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

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

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

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

#endif