]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/port/stack_trace.cc
add subtree-ish sources for 12.0.3
[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 the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same directory.
5 //
6 #include "port/stack_trace.h"
7
8 #if defined(ROCKSDB_LITE) || !(defined(ROCKSDB_BACKTRACE) || defined(OS_MACOSX)) || \
9 defined(CYGWIN) || defined(OS_FREEBSD) || defined(OS_SOLARIS)
10
11 // noop
12
13 namespace rocksdb {
14 namespace port {
15 void InstallStackTraceHandler() {}
16 void PrintStack(int first_frames_to_skip) {}
17 } // namespace port
18 } // namespace rocksdb
19
20 #else
21
22 #include <execinfo.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <cxxabi.h>
29
30 namespace rocksdb {
31 namespace port {
32
33 namespace {
34
35 #ifdef OS_LINUX
36 const char* GetExecutableName() {
37 static char name[1024];
38
39 char link[1024];
40 snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
41 auto read = readlink(link, name, sizeof(name) - 1);
42 if (-1 == read) {
43 return nullptr;
44 } else {
45 name[read] = 0;
46 return name;
47 }
48 }
49
50 void PrintStackTraceLine(const char* symbol, void* frame) {
51 static const char* executable = GetExecutableName();
52 if (symbol) {
53 fprintf(stderr, "%s ", symbol);
54 }
55 if (executable) {
56 // out source to addr2line, for the address translation
57 const int kLineMax = 256;
58 char cmd[kLineMax];
59 snprintf(cmd, kLineMax, "addr2line %p -e %s -f -C 2>&1", frame, executable);
60 auto f = popen(cmd, "r");
61 if (f) {
62 char line[kLineMax];
63 while (fgets(line, sizeof(line), f)) {
64 line[strlen(line) - 1] = 0; // remove newline
65 fprintf(stderr, "%s\t", line);
66 }
67 pclose(f);
68 }
69 } else {
70 fprintf(stderr, " %p", frame);
71 }
72
73 fprintf(stderr, "\n");
74 }
75 #elif defined(OS_MACOSX)
76
77 void PrintStackTraceLine(const char* symbol, void* frame) {
78 static int pid = getpid();
79 // out source to atos, for the address translation
80 const int kLineMax = 256;
81 char cmd[kLineMax];
82 snprintf(cmd, kLineMax, "xcrun atos %p -p %d 2>&1", frame, pid);
83 auto f = popen(cmd, "r");
84 if (f) {
85 char line[kLineMax];
86 while (fgets(line, sizeof(line), f)) {
87 line[strlen(line) - 1] = 0; // remove newline
88 fprintf(stderr, "%s\t", line);
89 }
90 pclose(f);
91 } else if (symbol) {
92 fprintf(stderr, "%s ", symbol);
93 }
94
95 fprintf(stderr, "\n");
96 }
97
98 #endif
99
100 } // namespace
101
102 void PrintStack(int first_frames_to_skip) {
103 const int kMaxFrames = 100;
104 void* frames[kMaxFrames];
105
106 auto num_frames = backtrace(frames, kMaxFrames);
107 auto symbols = backtrace_symbols(frames, num_frames);
108
109 for (int i = first_frames_to_skip; i < num_frames; ++i) {
110 fprintf(stderr, "#%-2d ", i - first_frames_to_skip);
111 PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]);
112 }
113 free(symbols);
114 }
115
116 static void StackTraceHandler(int sig) {
117 // reset to default handler
118 signal(sig, SIG_DFL);
119 fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig));
120 // skip the top three signal handler related frames
121 PrintStack(3);
122 // re-signal to default handler (so we still get core dump if needed...)
123 raise(sig);
124 }
125
126 void InstallStackTraceHandler() {
127 // just use the plain old signal as it's simple and sufficient
128 // for this use case
129 signal(SIGILL, StackTraceHandler);
130 signal(SIGSEGV, StackTraceHandler);
131 signal(SIGBUS, StackTraceHandler);
132 signal(SIGABRT, StackTraceHandler);
133 }
134
135 } // namespace port
136 } // namespace rocksdb
137
138 #endif