blob: 68f91d1377d54332696f2094d2217a58111dc3e0 [file] [log] [blame]
[email protected]380d8322012-02-28 21:35:441// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]58580352010-10-26 04:07:502// 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>
aviebe805c2015-12-24 08:20:289#include <stddef.h>
[email protected]58580352010-10-26 04:07:5010#include <stdio.h>
11#include <stdlib.h>
[email protected]0c6f3b0c2011-04-15 06:15:0412#include <sys/param.h>
[email protected]58580352010-10-26 04:07:5013#include <sys/stat.h>
[email protected]58580352010-10-26 04:07:5014#include <sys/types.h>
15#include <unistd.h>
16
dcheng093de9b2016-04-04 21:25:5117#include <memory>
[email protected]58580352010-10-26 04:07:5018#include <vector>
19
Hans Wennborgc3cffa62020-04-27 10:09:1220#include "base/check_op.h"
Sebastien Marchandbd02bc29e2020-03-11 15:53:3621#include "base/clang_profiling_buildflags.h"
Hans Wennborgc3cffa62020-04-27 10:09:1222#include "base/notreached.h"
Avi Drissmane3b70bf2019-01-04 19:50:2223#include "base/stl_util.h"
Hans Wennborgb3e433a2020-04-21 11:21:4024#include "base/strings/string_util.h"
bjaideepfbf03812016-10-14 23:02:1225#include "base/threading/platform_thread.h"
26#include "base/time/time.h"
dcheng093de9b2016-04-04 21:25:5127#include "build/build_config.h"
28
[email protected]58580352010-10-26 04:07:5029#if defined(__GLIBCXX__)
30#include <cxxabi.h>
31#endif
32
Avi Drissman5b286372020-07-28 21:59:3833#if defined(OS_APPLE)
[email protected]58580352010-10-26 04:07:5034#include <AvailabilityMacros.h>
35#endif
36
Avi Drissman5b286372020-07-28 21:59:3837#if defined(OS_APPLE) || defined(OS_BSD)
[email protected]94f8c952011-06-25 04:54:4138#include <sys/sysctl.h>
39#endif
40
[email protected]af824362011-12-04 14:19:4141#if defined(OS_FREEBSD)
42#include <sys/user.h>
43#endif
44
[email protected]a5c0fd982011-09-01 20:19:5345#include <ostream>
[email protected]58580352010-10-26 04:07:5046
Hans Wennborg7b533712020-06-22 20:52:2747#include "base/check.h"
hashimoto56a15912015-08-26 20:53:3448#include "base/debug/alias.h"
Tom Anderson5a1ce542019-03-08 20:19:2749#include "base/debug/debugging_buildflags.h"
50#include "base/environment.h"
51#include "base/files/file_util.h"
[email protected]2025d002012-11-14 20:54:3552#include "base/posix/eintr_wrapper.h"
Tom Anderson5a1ce542019-03-08 20:19:2753#include "base/process/process.h"
54#include "base/strings/string_number_conversions.h"
[email protected]eb62f7262013-03-30 14:29:0055#include "base/strings/string_piece.h"
[email protected]58580352010-10-26 04:07:5056
Sebastien Marchandbd02bc29e2020-03-11 15:53:3657#if BUILDFLAG(CLANG_PROFILING)
58#include "base/test/clang_profiling.h"
Yannic Bonenberger6801e6c2019-06-07 10:42:5359#endif
60
[email protected]58580352010-10-26 04:07:5061#if defined(USE_SYMBOLIZE)
62#include "base/third_party/symbolize/symbolize.h"
63#endif
64
65namespace base {
66namespace debug {
67
Avi Drissman5b286372020-07-28 21:59:3868#if defined(OS_APPLE) || defined(OS_BSD)
[email protected]58580352010-10-26 04:07:5069
70// Based on Apple's recommended method as described in
71// http://developer.apple.com/qa/qa2004/qa1361.html
72bool BeingDebugged() {
[email protected]1e218b72012-11-14 19:32:2373 // NOTE: This code MUST be async-signal safe (it's used by in-process
74 // stack dumping signal handler). NO malloc or stdio is allowed here.
75 //
76 // While some code used below may be async-signal unsafe, note how
77 // the result is cached (see |is_set| and |being_debugged| static variables
78 // right below). If this code is properly warmed-up early
79 // in the start-up process, it should be safe to use later.
80
[email protected]58580352010-10-26 04:07:5081 // If the process is sandboxed then we can't use the sysctl, so cache the
82 // value.
83 static bool is_set = false;
84 static bool being_debugged = false;
85
[email protected]1e218b72012-11-14 19:32:2386 if (is_set)
[email protected]58580352010-10-26 04:07:5087 return being_debugged;
[email protected]58580352010-10-26 04:07:5088
89 // Initialize mib, which tells sysctl what info we want. In this case,
90 // we're looking for information about a specific process ID.
91 int mib[] = {
92 CTL_KERN,
93 KERN_PROC,
94 KERN_PROC_PID,
95 getpid()
[email protected]88b49f72011-10-18 17:41:0796#if defined(OS_OPENBSD)
97 , sizeof(struct kinfo_proc),
98 0
99#endif
[email protected]58580352010-10-26 04:07:50100 };
101
102 // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and
103 // binary interfaces may change.
104 struct kinfo_proc info;
105 size_t info_size = sizeof(info);
106
[email protected]88b49f72011-10-18 17:41:07107#if defined(OS_OPENBSD)
Avi Drissmane3b70bf2019-01-04 19:50:22108 if (sysctl(mib, base::size(mib), NULL, &info_size, NULL, 0) < 0)
[email protected]88b49f72011-10-18 17:41:07109 return -1;
110
111 mib[5] = (info_size / sizeof(struct kinfo_proc));
112#endif
113
Avi Drissmane3b70bf2019-01-04 19:50:22114 int sysctl_result = sysctl(mib, base::size(mib), &info, &info_size, NULL, 0);
[email protected]58580352010-10-26 04:07:50115 DCHECK_EQ(sysctl_result, 0);
116 if (sysctl_result != 0) {
117 is_set = true;
118 being_debugged = false;
119 return being_debugged;
120 }
121
122 // This process is being debugged if the P_TRACED flag is set.
123 is_set = true;
[email protected]af824362011-12-04 14:19:41124#if defined(OS_FREEBSD)
125 being_debugged = (info.ki_flag & P_TRACED) != 0;
126#elif defined(OS_BSD)
[email protected]88b49f72011-10-18 17:41:07127 being_debugged = (info.p_flag & P_TRACED) != 0;
128#else
[email protected]58580352010-10-26 04:07:50129 being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
[email protected]88b49f72011-10-18 17:41:07130#endif
[email protected]58580352010-10-26 04:07:50131 return being_debugged;
132}
133
Erik Chen5c80c7a2019-08-29 22:48:15134void VerifyDebugger() {
135#if BUILDFLAG(ENABLE_LLDBINIT_WARNING)
136 if (Environment::Create()->HasVar("CHROMIUM_LLDBINIT_SOURCED"))
137 return;
138 if (!BeingDebugged())
139 return;
140 DCHECK(false)
141 << "Detected lldb without sourcing //tools/lldb/lldbinit.py. lldb may "
142 "not be able to find debug symbols. Please see debug instructions for "
143 "using //tools/lldb/lldbinit.py:\n"
John Palmerd29fc4362021-05-20 03:29:22144 "https://chromium.googlesource.com/chromium/src/+/main/docs/"
Erik Chen5c80c7a2019-08-29 22:48:15145 "lldbinit.md\n"
146 "To continue anyway, type 'continue' in lldb. To always skip this "
147 "check, define an environment variable CHROMIUM_LLDBINIT_SOURCED=1";
148#endif
149}
Tom Anderson5a1ce542019-03-08 20:19:27150
Sean McAllister39b8d342020-08-25 09:08:32151#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
152 defined(OS_AIX)
[email protected]58580352010-10-26 04:07:50153
154// We can look in /proc/self/status for TracerPid. We are likely used in crash
155// handling, so we are careful not to use the heap or have side effects.
156// Another option that is common is to try to ptrace yourself, but then we
157// can't detach without forking(), and that's not so great.
158// static
Tom Anderson5a1ce542019-03-08 20:19:27159Process GetDebuggerProcess() {
[email protected]1e218b72012-11-14 19:32:23160 // NOTE: This code MUST be async-signal safe (it's used by in-process
161 // stack dumping signal handler). NO malloc or stdio is allowed here.
162
[email protected]58580352010-10-26 04:07:50163 int status_fd = open("/proc/self/status", O_RDONLY);
164 if (status_fd == -1)
Tom Anderson5a1ce542019-03-08 20:19:27165 return Process();
[email protected]58580352010-10-26 04:07:50166
167 // We assume our line will be in the first 1024 characters and that we can
168 // read this much all at once. In practice this will generally be true.
169 // This simplifies and speeds up things considerably.
170 char buf[1024];
171
172 ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
[email protected]d89eec82013-12-03 14:10:59173 if (IGNORE_EINTR(close(status_fd)) < 0)
Tom Anderson5a1ce542019-03-08 20:19:27174 return Process();
[email protected]58580352010-10-26 04:07:50175
176 if (num_read <= 0)
Tom Anderson5a1ce542019-03-08 20:19:27177 return Process();
[email protected]58580352010-10-26 04:07:50178
179 StringPiece status(buf, num_read);
180 StringPiece tracer("TracerPid:\t");
181
182 StringPiece::size_type pid_index = status.find(tracer);
183 if (pid_index == StringPiece::npos)
Tom Anderson5a1ce542019-03-08 20:19:27184 return Process();
[email protected]58580352010-10-26 04:07:50185 pid_index += tracer.size();
Tom Anderson5a1ce542019-03-08 20:19:27186 StringPiece::size_type pid_end_index = status.find('\n', pid_index);
187 if (pid_end_index == StringPiece::npos)
188 return Process();
189
190 StringPiece pid_str(buf + pid_index, pid_end_index - pid_index);
191 int pid = 0;
192 if (!StringToInt(pid_str, &pid))
193 return Process();
194
195 return Process(pid);
196}
197
198bool BeingDebugged() {
199 return GetDebuggerProcess().IsValid();
200}
201
202void VerifyDebugger() {
203#if BUILDFLAG(ENABLE_GDBINIT_WARNING)
204 // Quick check before potentially slower GetDebuggerProcess().
205 if (Environment::Create()->HasVar("CHROMIUM_GDBINIT_SOURCED"))
206 return;
207
208 Process proc = GetDebuggerProcess();
209 if (!proc.IsValid())
210 return;
211
212 FilePath cmdline_file =
213 FilePath("/proc").Append(NumberToString(proc.Handle())).Append("cmdline");
214 std::string cmdline;
215 if (!ReadFileToString(cmdline_file, &cmdline))
216 return;
217
218 // /proc/*/cmdline separates arguments with null bytes, but we only care about
219 // the executable name, so interpret |cmdline| as a null-terminated C string
220 // to extract the exe portion.
221 StringPiece exe(cmdline.c_str());
222
223 DCHECK(ToLowerASCII(exe).find("gdb") == std::string::npos)
224 << "Detected gdb without sourcing //tools/gdb/gdbinit. gdb may not be "
225 "able to find debug symbols, and pretty-printing of STL types may not "
226 "work. Please see debug instructions for using //tools/gdb/gdbinit:\n"
John Palmerd29fc4362021-05-20 03:29:22227 "https://chromium.googlesource.com/chromium/src/+/main/docs/"
Tom Andersonf06ac382019-04-10 03:49:38228 "gdbinit.md\n"
229 "To continue anyway, type 'continue' in gdb. To always skip this "
230 "check, define an environment variable CHROMIUM_GDBINIT_SOURCED=1";
Tom Anderson5a1ce542019-03-08 20:19:27231#endif
[email protected]58580352010-10-26 04:07:50232}
233
[email protected]94f8c952011-06-25 04:54:41234#else
[email protected]58580352010-10-26 04:07:50235
[email protected]d0282962011-01-01 16:08:52236bool BeingDebugged() {
[email protected]58580352010-10-26 04:07:50237 NOTIMPLEMENTED();
238 return false;
239}
240
Tom Anderson5a1ce542019-03-08 20:19:27241void VerifyDebugger() {}
242
[email protected]af824362011-12-04 14:19:41243#endif
[email protected]58580352010-10-26 04:07:50244
245// We want to break into the debugger in Debug mode, and cause a crash dump in
246// Release mode. Breakpad behaves as follows:
247//
248// +-------+-----------------+-----------------+
249// | OS | Dump on SIGTRAP | Dump on SIGABRT |
250// +-------+-----------------+-----------------+
251// | Linux | N | Y |
252// | Mac | Y | N |
253// +-------+-----------------+-----------------+
254//
255// Thus we do the following:
[email protected]c706ecf82013-10-28 16:39:22256// Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send
257// SIGABRT
[email protected]58580352010-10-26 04:07:50258// Mac: Always send SIGTRAP.
259
[email protected]70d36252014-02-06 02:51:01260#if defined(ARCH_CPU_ARMEL)
[email protected]e35e1162013-10-29 19:45:32261#define DEBUG_BREAK_ASM() asm("bkpt 0")
[email protected]70d36252014-02-06 02:51:01262#elif defined(ARCH_CPU_ARM64)
263#define DEBUG_BREAK_ASM() asm("brk 0")
[email protected]e35e1162013-10-29 19:45:32264#elif defined(ARCH_CPU_MIPS_FAMILY)
265#define DEBUG_BREAK_ASM() asm("break 2")
266#elif defined(ARCH_CPU_X86_FAMILY)
267#define DEBUG_BREAK_ASM() asm("int3")
268#endif
269
Avi Drissman5b286372020-07-28 21:59:38270#if defined(NDEBUG) && !defined(OS_APPLE) && !defined(OS_ANDROID)
[email protected]58580352010-10-26 04:07:50271#define DEBUG_BREAK() abort()
[email protected]651d9c02010-12-01 07:36:54272#elif defined(OS_NACL)
273// The NaCl verifier doesn't let use use int3. For now, we call abort(). We
274// should ask for advice from some NaCl experts about the optimum thing here.
275// http://code.google.com/p/nativeclient/issues/detail?id=645
276#define DEBUG_BREAK() abort()
Avi Drissman5b286372020-07-28 21:59:38277#elif !defined(OS_APPLE)
[email protected]3132e35c2011-07-07 20:46:50278// Though Android has a "helpful" process called debuggerd to catch native
[email protected]480a2a32013-04-23 07:37:03279// signals on the general assumption that they are fatal errors. If no debugger
280// is attached, we call abort since Breakpad needs SIGABRT to create a dump.
281// When debugger is attached, for ARM platform the bkpt instruction appears
282// to cause SIGBUS which is trapped by debuggerd, and we've had great
283// difficulty continuing in a debugger once we stop from SIG triggered by native
284// code, use GDB to set |go| to 1 to resume execution; for X86 platform, use
285// "int3" to setup breakpiont and raise SIGTRAP.
[email protected]c706ecf82013-10-28 16:39:22286//
287// On other POSIX architectures, except Mac OS X, we use the same logic to
288// ensure that breakpad creates a dump on crashes while it is still possible to
289// use a debugger.
[email protected]901a5e382013-04-08 23:26:25290namespace {
291void DebugBreak() {
292 if (!BeingDebugged()) {
293 abort();
294 } else {
[email protected]e35e1162013-10-29 19:45:32295#if defined(DEBUG_BREAK_ASM)
296 DEBUG_BREAK_ASM();
[email protected]480a2a32013-04-23 07:37:03297#else
[email protected]901a5e382013-04-08 23:26:25298 volatile int go = 0;
Tom Anderson5a1ce542019-03-08 20:19:27299 while (!go)
300 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
[email protected]480a2a32013-04-23 07:37:03301#endif
[email protected]901a5e382013-04-08 23:26:25302 }
303}
304} // namespace
305#define DEBUG_BREAK() DebugBreak()
[email protected]e35e1162013-10-29 19:45:32306#elif defined(DEBUG_BREAK_ASM)
307#define DEBUG_BREAK() DEBUG_BREAK_ASM()
308#else
309#error "Don't know how to debug break on this architecture/OS"
[email protected]58580352010-10-26 04:07:50310#endif
311
312void BreakDebugger() {
Sebastien Marchandbd02bc29e2020-03-11 15:53:36313#if BUILDFLAG(CLANG_PROFILING)
314 WriteClangProfilingProfile();
Wezd2031d302018-08-16 23:34:25315#endif
316
[email protected]1e218b72012-11-14 19:32:23317 // NOTE: This code MUST be async-signal safe (it's used by in-process
318 // stack dumping signal handler). NO malloc or stdio is allowed here.
319
hashimoto56a15912015-08-26 20:53:34320 // Linker's ICF feature may merge this function with other functions with the
321 // same definition (e.g. any function whose sole job is to call abort()) and
322 // it may confuse the crash report processing system. http://crbug.com/508489
323 static int static_variable_to_make_this_function_unique = 0;
Tom Anderson5a1ce542019-03-08 20:19:27324 Alias(&static_variable_to_make_this_function_unique);
hashimoto56a15912015-08-26 20:53:34325
[email protected]58580352010-10-26 04:07:50326 DEBUG_BREAK();
[email protected]b3e58442012-06-29 06:39:27327#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
328 // For Android development we always build release (debug builds are
329 // unmanageably large), so the unofficial build is used for debugging. It is
330 // helpful to be able to insert BreakDebugger() statements in the source,
331 // attach the debugger, inspect the state of the program and then resume it by
332 // setting the 'go' variable above.
333#elif defined(NDEBUG)
334 // Terminate the program after signaling the debug break.
Nico Weberd9d917c02020-03-20 11:10:20335 // When DEBUG_BREAK() expands to abort(), this is unreachable code. Rather
336 // than carefully tracking in which cases DEBUG_BREAK()s is noreturn, just
337 // disable the unreachable code warning here.
338#pragma GCC diagnostic push
339#pragma GCC diagnostic ignored "-Wunreachable-code"
[email protected]f355c562011-01-21 05:02:17340 _exit(1);
Nico Weberd9d917c02020-03-20 11:10:20341#pragma GCC diagnostic pop
[email protected]f355c562011-01-21 05:02:17342#endif
[email protected]58580352010-10-26 04:07:50343}
344
345} // namespace debug
346} // namespace base