]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/port/stack_trace.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / port / stack_trace.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 //
6 #include "port/stack_trace.h"
7
8 #if defined(ROCKSDB_LITE) || \
9 !(defined(ROCKSDB_BACKTRACE) || defined(OS_MACOSX)) || defined(CYGWIN) || \
10 defined(OS_FREEBSD) || defined(OS_SOLARIS) || defined(OS_WIN)
11
12 // noop
13
14 namespace ROCKSDB_NAMESPACE {
15 namespace port {
16 void InstallStackTraceHandler() {}
17 void PrintStack(int /*first_frames_to_skip*/) {}
18 void PrintAndFreeStack(void* /*callstack*/, int /*num_frames*/) {}
19 void* SaveStack(int* /*num_frames*/, int /*first_frames_to_skip*/) {
20 return nullptr;
21 }
22 } // namespace port
23 } // namespace ROCKSDB_NAMESPACE
24
25 #else
26
27 #include <execinfo.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <cxxabi.h>
34
35 namespace ROCKSDB_NAMESPACE {
36 namespace port {
37
38 namespace {
39
40 #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD)
41 const char* GetExecutableName() {
42 static char name[1024];
43
44 char link[1024];
45 snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
46 auto read = readlink(link, name, sizeof(name) - 1);
47 if (-1 == read) {
48 return nullptr;
49 } else {
50 name[read] = 0;
51 return name;
52 }
53 }
54
55 void PrintStackTraceLine(const char* symbol, void* frame) {
56 static const char* executable = GetExecutableName();
57 if (symbol) {
58 fprintf(stderr, "%s ", symbol);
59 }
60 if (executable) {
61 // out source to addr2line, for the address translation
62 const int kLineMax = 256;
63 char cmd[kLineMax];
64 snprintf(cmd, kLineMax, "addr2line %p -e %s -f -C 2>&1", frame, executable);
65 auto f = popen(cmd, "r");
66 if (f) {
67 char line[kLineMax];
68 while (fgets(line, sizeof(line), f)) {
69 line[strlen(line) - 1] = 0; // remove newline
70 fprintf(stderr, "%s\t", line);
71 }
72 pclose(f);
73 }
74 } else {
75 fprintf(stderr, " %p", frame);
76 }
77
78 fprintf(stderr, "\n");
79 }
80 #elif defined(OS_MACOSX)
81
82 void PrintStackTraceLine(const char* symbol, void* frame) {
83 static int pid = getpid();
84 // out source to atos, for the address translation
85 const int kLineMax = 256;
86 char cmd[kLineMax];
87 snprintf(cmd, kLineMax, "xcrun atos %p -p %d 2>&1", frame, pid);
88 auto f = popen(cmd, "r");
89 if (f) {
90 char line[kLineMax];
91 while (fgets(line, sizeof(line), f)) {
92 line[strlen(line) - 1] = 0; // remove newline
93 fprintf(stderr, "%s\t", line);
94 }
95 pclose(f);
96 } else if (symbol) {
97 fprintf(stderr, "%s ", symbol);
98 }
99
100 fprintf(stderr, "\n");
101 }
102
103 #endif
104
105 } // namespace
106
107 void PrintStack(void* frames[], int num_frames) {
108 auto symbols = backtrace_symbols(frames, num_frames);
109
110 for (int i = 0; i < num_frames; ++i) {
111 fprintf(stderr, "#%-2d ", i);
112 PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]);
113 }
114 free(symbols);
115 }
116
117 void PrintStack(int first_frames_to_skip) {
118 const int kMaxFrames = 100;
119 void* frames[kMaxFrames];
120
121 auto num_frames = backtrace(frames, kMaxFrames);
122 PrintStack(&frames[first_frames_to_skip], num_frames - first_frames_to_skip);
123 }
124
125 void PrintAndFreeStack(void* callstack, int num_frames) {
126 PrintStack(static_cast<void**>(callstack), num_frames);
127 free(callstack);
128 }
129
130 void* SaveStack(int* num_frames, int first_frames_to_skip) {
131 const int kMaxFrames = 100;
132 void* frames[kMaxFrames];
133
134 auto count = backtrace(frames, kMaxFrames);
135 *num_frames = count - first_frames_to_skip;
136 void* callstack = malloc(sizeof(void*) * *num_frames);
137 memcpy(callstack, &frames[first_frames_to_skip], sizeof(void*) * *num_frames);
138 return callstack;
139 }
140
141 static void StackTraceHandler(int sig) {
142 // reset to default handler
143 signal(sig, SIG_DFL);
144 fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig));
145 // skip the top three signal handler related frames
146 PrintStack(3);
147 // re-signal to default handler (so we still get core dump if needed...)
148 raise(sig);
149 }
150
151 void InstallStackTraceHandler() {
152 // just use the plain old signal as it's simple and sufficient
153 // for this use case
154 signal(SIGILL, StackTraceHandler);
155 signal(SIGSEGV, StackTraceHandler);
156 signal(SIGBUS, StackTraceHandler);
157 signal(SIGABRT, StackTraceHandler);
158 }
159
160 } // namespace port
161 } // namespace ROCKSDB_NAMESPACE
162
163 #endif