/Users/deen/code/yugabyte-db/src/yb/rocksdb/port/stack_trace.cc
Line | Count | Source (jump to first uncovered line) |
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 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | #include "yb/rocksdb/port/stack_trace.h" |
21 | | |
22 | | #if defined(ROCKSDB_LITE) || !(defined(__linux__) || defined(OS_MACOSX)) || \ |
23 | | defined(CYGWIN) |
24 | | |
25 | | // noop |
26 | | |
27 | | namespace rocksdb { |
28 | | namespace port { |
29 | | void InstallStackTraceHandler() {} |
30 | | void PrintStack(int first_frames_to_skip) {} |
31 | | } // namespace port |
32 | | } // namespace rocksdb |
33 | | |
34 | | #else |
35 | | |
36 | | #include <execinfo.h> |
37 | | #include <signal.h> |
38 | | #include <stdio.h> |
39 | | #include <stdlib.h> |
40 | | #include <string.h> |
41 | | #include <unistd.h> |
42 | | #include <cxxabi.h> |
43 | | |
44 | | namespace rocksdb { |
45 | | namespace port { |
46 | | |
47 | | namespace { |
48 | | |
49 | | #ifdef __linux__ |
50 | | const char* GetExecutableName() { |
51 | | static char name[1024]; |
52 | | |
53 | | char link[1024]; |
54 | | snprintf(link, sizeof(link), "/proc/%d/exe", getpid()); |
55 | | auto read = readlink(link, name, sizeof(name) - 1); |
56 | | if (-1 == read) { |
57 | | return nullptr; |
58 | | } else { |
59 | | name[read] = 0; |
60 | | return name; |
61 | | } |
62 | | } |
63 | | |
64 | | void PrintStackTraceLine(const char* symbol, void* frame) { |
65 | | static const char* executable = GetExecutableName(); |
66 | | if (symbol) { |
67 | | fprintf(stderr, "%s ", symbol); |
68 | | } |
69 | | if (executable) { |
70 | | // out source to addr2line, for the address translation |
71 | | const int kLineMax = 256; |
72 | | char cmd[kLineMax]; |
73 | | snprintf(cmd, kLineMax, "addr2line %p -e %s -f -C 2>&1", frame, executable); |
74 | | auto f = popen(cmd, "r"); |
75 | | if (f) { |
76 | | char line[kLineMax]; |
77 | | while (fgets(line, sizeof(line), f)) { |
78 | | line[strlen(line) - 1] = 0; // remove newline |
79 | | fprintf(stderr, "%s\t", line); |
80 | | } |
81 | | pclose(f); |
82 | | } |
83 | | } else { |
84 | | fprintf(stderr, " %p", frame); |
85 | | } |
86 | | |
87 | | fprintf(stderr, "\n"); |
88 | | } |
89 | | #elif defined(OS_MACOSX) |
90 | | |
91 | 47 | void PrintStackTraceLine(const char* symbol, void* frame) { |
92 | 47 | static int pid = getpid(); |
93 | | // out source to atos, for the address translation |
94 | 47 | const int kLineMax = 256; |
95 | 47 | char cmd[kLineMax]; |
96 | 47 | snprintf(cmd, kLineMax, "xcrun atos %p -p %d 2>&1", frame, pid); |
97 | 47 | auto f = popen(cmd, "r"); |
98 | 47 | if (f) { |
99 | 23 | char line[kLineMax]; |
100 | 46 | while (fgets(line, sizeof(line), f)) { |
101 | 23 | line[strlen(line) - 1] = 0; // remove newline |
102 | 23 | fprintf(stderr, "%s\t", line); |
103 | 23 | } |
104 | 23 | pclose(f); |
105 | 24 | } else if (symbol) { |
106 | 24 | fprintf(stderr, "%s ", symbol); |
107 | 24 | } |
108 | | |
109 | 47 | fprintf(stderr, "\n"); |
110 | 47 | } |
111 | | |
112 | | #endif |
113 | | |
114 | | } // namespace |
115 | | |
116 | 2 | void PrintStack(int first_frames_to_skip) { |
117 | 2 | const int kMaxFrames = 100; |
118 | 2 | void* frames[kMaxFrames]; |
119 | | |
120 | 2 | auto num_frames = backtrace(frames, kMaxFrames); |
121 | 2 | auto symbols = backtrace_symbols(frames, num_frames); |
122 | | |
123 | 49 | for (int i = first_frames_to_skip; i < num_frames; ++i) { |
124 | 47 | fprintf(stderr, "#%-2d ", i - first_frames_to_skip); |
125 | 47 | PrintStackTraceLine((symbols != nullptr) ? symbols[i] : nullptr, frames[i]); |
126 | 47 | } |
127 | 2 | } |
128 | | |
129 | 2 | static void StackTraceHandler(int sig) { |
130 | | // reset to default handler |
131 | 2 | signal(sig, SIG_DFL); |
132 | 2 | fprintf(stderr, "Received signal %d (%s)\n", sig, strsignal(sig)); |
133 | | // skip the top three signal handler related frames |
134 | 2 | PrintStack(3); |
135 | | // re-signal to default handler (so we still get core dump if needed...) |
136 | 2 | raise(sig); |
137 | 2 | } |
138 | | |
139 | 563 | void InstallStackTraceHandler() { |
140 | | // just use the plain old signal as it's simple and sufficient |
141 | | // for this use case |
142 | 563 | signal(SIGILL, StackTraceHandler); |
143 | 563 | signal(SIGSEGV, StackTraceHandler); |
144 | 563 | signal(SIGBUS, StackTraceHandler); |
145 | 563 | signal(SIGABRT, StackTraceHandler); |
146 | 563 | } |
147 | | |
148 | | } // namespace port |
149 | | } // namespace rocksdb |
150 | | |
151 | | #endif |