1 // Copyright 2012 The Chromium Authors
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 "base/debug/debugger.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stddef.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 <memory>
18 #include <string_view>
19
20 #include "base/check_op.h"
21 #include "base/notimplemented.h"
22 #include "base/strings/string_util.h"
23 #include "base/threading/platform_thread.h"
24 #include "base/time/time.h"
25 #include "build/build_config.h"
26
27 #if defined(__GLIBCXX__)
28 #include <cxxabi.h>
29 #endif
30
31 #if BUILDFLAG(IS_APPLE)
32 #include <AvailabilityMacros.h>
33 #endif
34
35 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_BSD)
36 #include <sys/sysctl.h>
37 #endif
38
39 #if BUILDFLAG(IS_FREEBSD)
40 #include <sys/user.h>
41 #endif
42
43 #include <ostream>
44
45 #include "base/check.h"
46 #include "base/debug/alias.h"
47 #include "base/debug/debugging_buildflags.h"
48 #include "base/environment.h"
49 #include "base/files/file_util.h"
50 #include "base/posix/eintr_wrapper.h"
51 #include "base/process/process.h"
52 #include "base/strings/string_number_conversions.h"
53
54 #if defined(USE_SYMBOLIZE)
55 #include "base/third_party/symbolize/symbolize.h" // nogncheck
56 #endif
57
58 namespace base {
59 namespace debug {
60
61 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_BSD)
62
63 // Based on Apple's recommended method as described in
64 // http://developer.apple.com/qa/qa2004/qa1361.html
BeingDebugged()65 bool BeingDebugged() {
66 // NOTE: This code MUST be async-signal safe (it's used by in-process
67 // stack dumping signal handler). NO malloc or stdio is allowed here.
68 //
69 // While some code used below may be async-signal unsafe, note how
70 // the result is cached (see |is_set| and |being_debugged| static variables
71 // right below). If this code is properly warmed-up early
72 // in the start-up process, it should be safe to use later.
73
74 // If the process is sandboxed then we can't use the sysctl, so cache the
75 // value.
76 static bool is_set = false;
77 static bool being_debugged = false;
78
79 if (is_set)
80 return being_debugged;
81
82 // Initialize mib, which tells sysctl what info we want. In this case,
83 // we're looking for information about a specific process ID.
84 int mib[] = {
85 CTL_KERN,
86 KERN_PROC,
87 KERN_PROC_PID,
88 getpid()
89 #if BUILDFLAG(IS_OPENBSD)
90 ,
91 sizeof(struct kinfo_proc),
92 0
93 #endif
94 };
95
96 // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and
97 // binary interfaces may change.
98 struct kinfo_proc info;
99 size_t info_size = sizeof(info);
100
101 #if BUILDFLAG(IS_OPENBSD)
102 if (sysctl(mib, std::size(mib), NULL, &info_size, NULL, 0) < 0)
103 return -1;
104
105 mib[5] = (info_size / sizeof(struct kinfo_proc));
106 #endif
107
108 int sysctl_result = sysctl(mib, std::size(mib), &info, &info_size, NULL, 0);
109 DCHECK_EQ(sysctl_result, 0);
110 if (sysctl_result != 0) {
111 is_set = true;
112 being_debugged = false;
113 return being_debugged;
114 }
115
116 // This process is being debugged if the P_TRACED flag is set.
117 is_set = true;
118 #if BUILDFLAG(IS_FREEBSD)
119 being_debugged = (info.ki_flag & P_TRACED) != 0;
120 #elif BUILDFLAG(IS_BSD)
121 being_debugged = (info.p_flag & P_TRACED) != 0;
122 #else
123 being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
124 #endif
125 return being_debugged;
126 }
127
VerifyDebugger()128 void VerifyDebugger() {
129 #if BUILDFLAG(ENABLE_LLDBINIT_WARNING)
130 if (Environment::Create()->HasVar("CHROMIUM_LLDBINIT_SOURCED"))
131 return;
132 if (!BeingDebugged())
133 return;
134 DCHECK(false)
135 << "Detected lldb without sourcing //tools/lldb/lldbinit.py. lldb may "
136 "not be able to find debug symbols. Please see debug instructions for "
137 "using //tools/lldb/lldbinit.py:\n"
138 "https://chromium.googlesource.com/chromium/src/+/main/docs/"
139 "lldbinit.md\n"
140 "To continue anyway, type 'continue' in lldb. To always skip this "
141 "check, define an environment variable CHROMIUM_LLDBINIT_SOURCED=1";
142 #endif
143 }
144
145 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
146 BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_AIX)
147
148 // We can look in /proc/self/status for TracerPid. We are likely used in crash
149 // handling, so we are careful not to use the heap or have side effects.
150 // Another option that is common is to try to ptrace yourself, but then we
151 // can't detach without forking(), and that's not so great.
152 // static
153 Process GetDebuggerProcess() {
154 // NOTE: This code MUST be async-signal safe (it's used by in-process
155 // stack dumping signal handler). NO malloc or stdio is allowed here.
156
157 int status_fd = open("/proc/self/status", O_RDONLY);
158 if (status_fd == -1)
159 return Process();
160
161 // We assume our line will be in the first 1024 characters and that we can
162 // read this much all at once. In practice this will generally be true.
163 // This simplifies and speeds up things considerably.
164 char buf[1024];
165
166 ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
167 if (IGNORE_EINTR(close(status_fd)) < 0)
168 return Process();
169
170 if (num_read <= 0)
171 return Process();
172
173 std::string_view status(buf, static_cast<size_t>(num_read));
174 std::string_view tracer("TracerPid:\t");
175
176 StringPiece::size_type pid_index = status.find(tracer);
177 if (pid_index == StringPiece::npos)
178 return Process();
179 pid_index += tracer.size();
180 StringPiece::size_type pid_end_index = status.find('\n', pid_index);
181 if (pid_end_index == StringPiece::npos)
182 return Process();
183
184 std::string_view pid_str(buf + pid_index, pid_end_index - pid_index);
185 int pid = 0;
186 if (!StringToInt(pid_str, &pid))
187 return Process();
188
189 return Process(pid);
190 }
191
192 bool BeingDebugged() {
193 return GetDebuggerProcess().IsValid();
194 }
195
196 void VerifyDebugger() {
197 #if BUILDFLAG(ENABLE_GDBINIT_WARNING)
198 // Quick check before potentially slower GetDebuggerProcess().
199 if (Environment::Create()->HasVar("CHROMIUM_GDBINIT_SOURCED"))
200 return;
201
202 Process proc = GetDebuggerProcess();
203 if (!proc.IsValid())
204 return;
205
206 FilePath cmdline_file =
207 FilePath("/proc").Append(NumberToString(proc.Handle())).Append("cmdline");
208 std::string cmdline;
209 if (!ReadFileToString(cmdline_file, &cmdline))
210 return;
211
212 // /proc/*/cmdline separates arguments with null bytes, but we only care about
213 // the executable name, so interpret |cmdline| as a null-terminated C string
214 // to extract the exe portion.
215 std::string_view exe(cmdline.c_str());
216
217 DCHECK(ToLowerASCII(exe).find("gdb") == std::string::npos)
218 << "Detected gdb without sourcing //tools/gdb/gdbinit. gdb may not be "
219 "able to find debug symbols, and pretty-printing of STL types may not "
220 "work. Please see debug instructions for using //tools/gdb/gdbinit:\n"
221 "https://chromium.googlesource.com/chromium/src/+/main/docs/"
222 "gdbinit.md\n"
223 "To continue anyway, type 'continue' in gdb. To always skip this "
224 "check, define an environment variable CHROMIUM_GDBINIT_SOURCED=1";
225 #endif
226 }
227
228 #else
229
230 bool BeingDebugged() {
231 NOTIMPLEMENTED();
232 return false;
233 }
234
235 void VerifyDebugger() {}
236
237 #endif
238
239 // We want to break into the debugger in Debug mode, and cause a crash dump in
240 // Release mode. Breakpad behaves as follows:
241 //
242 // +-------+-----------------+-----------------+
243 // | OS | Dump on SIGTRAP | Dump on SIGABRT |
244 // +-------+-----------------+-----------------+
245 // | Linux | N | Y |
246 // | Mac | Y | N |
247 // +-------+-----------------+-----------------+
248 //
249 // Thus we do the following:
250 // Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send
251 // SIGABRT
252 // Mac: Always send SIGTRAP.
253
254 #if defined(ARCH_CPU_ARMEL)
255 #define DEBUG_BREAK_ASM() asm("bkpt 0")
256 #elif defined(ARCH_CPU_ARM64)
257 #define DEBUG_BREAK_ASM() asm("brk 0")
258 #elif defined(ARCH_CPU_MIPS_FAMILY)
259 #define DEBUG_BREAK_ASM() asm("break 2")
260 #elif defined(ARCH_CPU_X86_FAMILY)
261 #define DEBUG_BREAK_ASM() asm("int3")
262 #endif
263
264 #if defined(NDEBUG) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID)
265 #define DEBUG_BREAK() abort()
266 #elif BUILDFLAG(IS_NACL)
267 // The NaCl verifier doesn't let use use int3. For now, we call abort(). We
268 // should ask for advice from some NaCl experts about the optimum thing here.
269 // http://code.google.com/p/nativeclient/issues/detail?id=645
270 #define DEBUG_BREAK() abort()
271 #elif !BUILDFLAG(IS_APPLE)
272 // Though Android has a "helpful" process called debuggerd to catch native
273 // signals on the general assumption that they are fatal errors. If no debugger
274 // is attached, we call abort since Breakpad needs SIGABRT to create a dump.
275 // When debugger is attached, for ARM platform the bkpt instruction appears
276 // to cause SIGBUS which is trapped by debuggerd, and we've had great
277 // difficulty continuing in a debugger once we stop from SIG triggered by native
278 // code, use GDB to set |go| to 1 to resume execution; for X86 platform, use
279 // "int3" to setup breakpiont and raise SIGTRAP.
280 //
281 // On other POSIX architectures, except Mac OS X, we use the same logic to
282 // ensure that breakpad creates a dump on crashes while it is still possible to
283 // use a debugger.
284 namespace {
DebugBreak()285 void DebugBreak() {
286 if (!BeingDebugged()) {
287 abort();
288 } else {
289 #if defined(DEBUG_BREAK_ASM)
290 DEBUG_BREAK_ASM();
291 #else
292 volatile int go = 0;
293 while (!go)
294 PlatformThread::Sleep(Milliseconds(100));
295 #endif
296 }
297 }
298 } // namespace
299 #define DEBUG_BREAK() DebugBreak()
300 #elif defined(DEBUG_BREAK_ASM)
301 #define DEBUG_BREAK() DEBUG_BREAK_ASM()
302 #else
303 #error "Don't know how to debug break on this architecture/OS"
304 #endif
305
BreakDebuggerAsyncSafe()306 void BreakDebuggerAsyncSafe() {
307 // NOTE: This code MUST be async-signal safe (it's used by in-process
308 // stack dumping signal handler). NO malloc or stdio is allowed here.
309
310 // Linker's ICF feature may merge this function with other functions with the
311 // same definition (e.g. any function whose sole job is to call abort()) and
312 // it may confuse the crash report processing system. http://crbug.com/508489
313 static int static_variable_to_make_this_function_unique = 0;
314 Alias(&static_variable_to_make_this_function_unique);
315
316 DEBUG_BREAK();
317 #if BUILDFLAG(IS_ANDROID) && !defined(OFFICIAL_BUILD)
318 // For Android development we always build release (debug builds are
319 // unmanageably large), so the unofficial build is used for debugging. It is
320 // helpful to be able to insert BreakDebugger() statements in the source,
321 // attach the debugger, inspect the state of the program and then resume it by
322 // setting the 'go' variable above.
323 #elif defined(NDEBUG)
324 // Terminate the program after signaling the debug break.
325 // When DEBUG_BREAK() expands to abort(), this is unreachable code. Rather
326 // than carefully tracking in which cases DEBUG_BREAK()s is noreturn, just
327 // disable the unreachable code warning here.
328 #pragma GCC diagnostic push
329 #pragma GCC diagnostic ignored "-Wunreachable-code"
330 _exit(1);
331 #pragma GCC diagnostic pop
332 #endif
333 }
334
335 } // namespace debug
336 } // namespace base
337