/src/brpc/src/butil/debug/debugger_posix.cc
Line | Count | Source |
1 | | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 | | // Use of this source code is governed by a BSD-style license that can be |
3 | | // found in the LICENSE file. |
4 | | |
5 | | #include "butil/debug/debugger.h" |
6 | | #include "butil/build_config.h" |
7 | | |
8 | | #include <errno.h> |
9 | | #include <fcntl.h> |
10 | | #include <stdio.h> |
11 | | #include <stdlib.h> |
12 | | #include <sys/param.h> |
13 | | #include <sys/stat.h> |
14 | | #include <sys/types.h> |
15 | | #include <unistd.h> |
16 | | |
17 | | #include <vector> |
18 | | |
19 | | #if defined(__GLIBCXX__) |
20 | | #include <cxxabi.h> |
21 | | #endif |
22 | | |
23 | | #if defined(OS_MACOSX) |
24 | | #include <AvailabilityMacros.h> |
25 | | #endif |
26 | | |
27 | | #if defined(OS_MACOSX) || defined(OS_BSD) |
28 | | #include <sys/sysctl.h> |
29 | | #endif |
30 | | |
31 | | #if defined(OS_FREEBSD) |
32 | | #include <sys/user.h> |
33 | | #endif |
34 | | |
35 | | #include <ostream> |
36 | | |
37 | | #include "butil/basictypes.h" |
38 | | #include "butil/logging.h" |
39 | | #include "butil/memory/scoped_ptr.h" |
40 | | #include "butil/posix/eintr_wrapper.h" |
41 | | #include "butil/safe_strerror_posix.h" |
42 | | #include "butil/strings/string_piece.h" |
43 | | |
44 | | #if defined(USE_SYMBOLIZE) |
45 | | #include "butil/third_party/symbolize/symbolize.h" |
46 | | #endif |
47 | | |
48 | | #if defined(OS_ANDROID) |
49 | | #include "butil/threading/platform_thread.h" |
50 | | #endif |
51 | | |
52 | | namespace butil { |
53 | | namespace debug { |
54 | | |
55 | | #if defined(OS_MACOSX) || defined(OS_BSD) |
56 | | |
57 | | // Based on Apple's recommended method as described in |
58 | | // http://developer.apple.com/qa/qa2004/qa1361.html |
59 | | bool BeingDebugged() { |
60 | | // NOTE: This code MUST be async-signal safe (it's used by in-process |
61 | | // stack dumping signal handler). NO malloc or stdio is allowed here. |
62 | | // |
63 | | // While some code used below may be async-signal unsafe, note how |
64 | | // the result is cached (see |is_set| and |being_debugged| static variables |
65 | | // right below). If this code is properly warmed-up early |
66 | | // in the start-up process, it should be safe to use later. |
67 | | |
68 | | // If the process is sandboxed then we can't use the sysctl, so cache the |
69 | | // value. |
70 | | static bool is_set = false; |
71 | | static bool being_debugged = false; |
72 | | |
73 | | if (is_set) |
74 | | return being_debugged; |
75 | | |
76 | | // Initialize mib, which tells sysctl what info we want. In this case, |
77 | | // we're looking for information about a specific process ID. |
78 | | int mib[] = { |
79 | | CTL_KERN, |
80 | | KERN_PROC, |
81 | | KERN_PROC_PID, |
82 | | getpid() |
83 | | #if defined(OS_OPENBSD) |
84 | | , sizeof(struct kinfo_proc), |
85 | | 0 |
86 | | #endif |
87 | | }; |
88 | | |
89 | | // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and |
90 | | // binary interfaces may change. |
91 | | struct kinfo_proc info; |
92 | | size_t info_size = sizeof(info); |
93 | | |
94 | | #if defined(OS_OPENBSD) |
95 | | if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0) |
96 | | return -1; |
97 | | |
98 | | mib[5] = (info_size / sizeof(struct kinfo_proc)); |
99 | | #endif |
100 | | |
101 | | int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0); |
102 | | DCHECK_EQ(sysctl_result, 0); |
103 | | if (sysctl_result != 0) { |
104 | | is_set = true; |
105 | | being_debugged = false; |
106 | | return being_debugged; |
107 | | } |
108 | | |
109 | | // This process is being debugged if the P_TRACED flag is set. |
110 | | is_set = true; |
111 | | #if defined(OS_FREEBSD) |
112 | | being_debugged = (info.ki_flag & P_TRACED) != 0; |
113 | | #elif defined(OS_BSD) |
114 | | being_debugged = (info.p_flag & P_TRACED) != 0; |
115 | | #else |
116 | | being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0; |
117 | | #endif |
118 | | return being_debugged; |
119 | | } |
120 | | |
121 | | #elif defined(OS_LINUX) || defined(OS_ANDROID) |
122 | | |
123 | | // We can look in /proc/self/status for TracerPid. We are likely used in crash |
124 | | // handling, so we are careful not to use the heap or have side effects. |
125 | | // Another option that is common is to try to ptrace yourself, but then we |
126 | | // can't detach without forking(), and that's not so great. |
127 | | // static |
128 | 0 | bool BeingDebugged() { |
129 | | // NOTE: This code MUST be async-signal safe (it's used by in-process |
130 | | // stack dumping signal handler). NO malloc or stdio is allowed here. |
131 | |
|
132 | 0 | int status_fd = open("/proc/self/status", O_RDONLY); |
133 | 0 | if (status_fd == -1) |
134 | 0 | return false; |
135 | | |
136 | | // We assume our line will be in the first 1024 characters and that we can |
137 | | // read this much all at once. In practice this will generally be true. |
138 | | // This simplifies and speeds up things considerably. |
139 | 0 | char buf[1024]; |
140 | |
|
141 | 0 | ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf))); |
142 | 0 | if (IGNORE_EINTR(close(status_fd)) < 0) |
143 | 0 | return false; |
144 | | |
145 | 0 | if (num_read <= 0) |
146 | 0 | return false; |
147 | | |
148 | 0 | StringPiece status(buf, num_read); |
149 | 0 | StringPiece tracer("TracerPid:\t"); |
150 | |
|
151 | 0 | StringPiece::size_type pid_index = status.find(tracer); |
152 | 0 | if (pid_index == StringPiece::npos) |
153 | 0 | return false; |
154 | | |
155 | | // Our pid is 0 without a debugger, assume this for any pid starting with 0. |
156 | 0 | pid_index += tracer.size(); |
157 | 0 | return pid_index < status.size() && status[pid_index] != '0'; |
158 | 0 | } |
159 | | |
160 | | #else |
161 | | |
162 | | bool BeingDebugged() { |
163 | | NOTIMPLEMENTED(); |
164 | | return false; |
165 | | } |
166 | | |
167 | | #endif |
168 | | |
169 | | // We want to break into the debugger in Debug mode, and cause a crash dump in |
170 | | // Release mode. Breakpad behaves as follows: |
171 | | // |
172 | | // +-------+-----------------+-----------------+ |
173 | | // | OS | Dump on SIGTRAP | Dump on SIGABRT | |
174 | | // +-------+-----------------+-----------------+ |
175 | | // | Linux | N | Y | |
176 | | // | Mac | Y | N | |
177 | | // +-------+-----------------+-----------------+ |
178 | | // |
179 | | // Thus we do the following: |
180 | | // Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send |
181 | | // SIGABRT |
182 | | // Mac: Always send SIGTRAP. |
183 | | |
184 | | #if defined(ARCH_CPU_ARMEL) |
185 | | #define DEBUG_BREAK_ASM() asm("bkpt 0") |
186 | | #elif defined(ARCH_CPU_ARM64) |
187 | | #define DEBUG_BREAK_ASM() asm("brk 0") |
188 | | #elif defined(ARCH_CPU_LOONGARCH64_FAMILY) |
189 | | #define DEBUG_BREAK_ASM() asm("break 0") |
190 | | #elif defined(ARCH_CPU_MIPS_FAMILY) |
191 | | #define DEBUG_BREAK_ASM() asm("break 2") |
192 | | #elif defined(ARCH_CPU_X86_FAMILY) |
193 | 0 | #define DEBUG_BREAK_ASM() asm("int3") |
194 | | #endif |
195 | | |
196 | | #if defined(NDEBUG) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
197 | | #define DEBUG_BREAK() abort() |
198 | | #elif defined(OS_NACL) |
199 | | // The NaCl verifier doesn't let use use int3. For now, we call abort(). We |
200 | | // should ask for advice from some NaCl experts about the optimum thing here. |
201 | | // http://code.google.com/p/nativeclient/issues/detail?id=645 |
202 | | #define DEBUG_BREAK() abort() |
203 | | #elif !defined(OS_MACOSX) |
204 | | // Though Android has a "helpful" process called debuggerd to catch native |
205 | | // signals on the general assumption that they are fatal errors. If no debugger |
206 | | // is attached, we call abort since Breakpad needs SIGABRT to create a dump. |
207 | | // When debugger is attached, for ARM platform the bkpt instruction appears |
208 | | // to cause SIGBUS which is trapped by debuggerd, and we've had great |
209 | | // difficulty continuing in a debugger once we stop from SIG triggered by native |
210 | | // code, use GDB to set |go| to 1 to resume execution; for X86 platform, use |
211 | | // "int3" to setup breakpiont and raise SIGTRAP. |
212 | | // |
213 | | // On other POSIX architectures, except Mac OS X, we use the same logic to |
214 | | // ensure that breakpad creates a dump on crashes while it is still possible to |
215 | | // use a debugger. |
216 | | namespace { |
217 | 0 | void DebugBreak() { |
218 | 0 | if (!BeingDebugged()) { |
219 | 0 | abort(); |
220 | 0 | } else { |
221 | 0 | #if defined(DEBUG_BREAK_ASM) |
222 | 0 | DEBUG_BREAK_ASM(); |
223 | | #else |
224 | | volatile int go = 0; |
225 | | while (!go) { |
226 | | butil::PlatformThread::Sleep(butil::TimeDelta::FromMilliseconds(100)); |
227 | | } |
228 | | #endif |
229 | 0 | } |
230 | 0 | } |
231 | | } // namespace |
232 | 0 | #define DEBUG_BREAK() DebugBreak() |
233 | | #elif defined(DEBUG_BREAK_ASM) |
234 | | #define DEBUG_BREAK() DEBUG_BREAK_ASM() |
235 | | #else |
236 | | #error "Don't know how to debug break on this architecture/OS" |
237 | | #endif |
238 | | |
239 | 0 | void BreakDebugger() { |
240 | | // NOTE: This code MUST be async-signal safe (it's used by in-process |
241 | | // stack dumping signal handler). NO malloc or stdio is allowed here. |
242 | |
|
243 | 0 | DEBUG_BREAK(); |
244 | | #if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD) |
245 | | // For Android development we always build release (debug builds are |
246 | | // unmanageably large), so the unofficial build is used for debugging. It is |
247 | | // helpful to be able to insert BreakDebugger() statements in the source, |
248 | | // attach the debugger, inspect the state of the program and then resume it by |
249 | | // setting the 'go' variable above. |
250 | | #elif defined(NDEBUG) |
251 | | // Terminate the program after signaling the debug break. |
252 | | _exit(1); |
253 | | #endif |
254 | 0 | } |
255 | | |
256 | | } // namespace debug |
257 | | } // namespace butil |