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