debugger_posix.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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/stat.h>
13#if !defined(OS_NACL)
14#include <sys/sysctl.h>
15#endif
16#include <sys/types.h>
17#include <unistd.h>
18
19#include <string>
20#include <vector>
21
22#if defined(__GLIBCXX__)
23#include <cxxabi.h>
24#endif
25
26#if defined(OS_MACOSX)
27#include <AvailabilityMacros.h>
28#endif
29
30#include <iostream>
31
32#include "base/basictypes.h"
33#include "base/compat_execinfo.h"
34#include "base/eintr_wrapper.h"
35#include "base/logging.h"
36#include "base/safe_strerror_posix.h"
37#include "base/scoped_ptr.h"
38#include "base/string_piece.h"
39#include "base/stringprintf.h"
40
41#if defined(USE_SYMBOLIZE)
42#include "base/third_party/symbolize/symbolize.h"
43#endif
44
45namespace base {
46namespace debug {
47
48bool SpawnDebuggerOnProcess(unsigned /* process_id */) {
49  NOTIMPLEMENTED();
50  return false;
51}
52
53#if defined(OS_MACOSX)
54
55// Based on Apple's recommended method as described in
56// http://developer.apple.com/qa/qa2004/qa1361.html
57bool BeingDebugged() {
58  // If the process is sandboxed then we can't use the sysctl, so cache the
59  // value.
60  static bool is_set = false;
61  static bool being_debugged = false;
62
63  if (is_set) {
64    return being_debugged;
65  }
66
67  // Initialize mib, which tells sysctl what info we want.  In this case,
68  // we're looking for information about a specific process ID.
69  int mib[] = {
70    CTL_KERN,
71    KERN_PROC,
72    KERN_PROC_PID,
73    getpid()
74  };
75
76  // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
77  // binary interfaces may change.
78  struct kinfo_proc info;
79  size_t info_size = sizeof(info);
80
81  int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
82  DCHECK_EQ(sysctl_result, 0);
83  if (sysctl_result != 0) {
84    is_set = true;
85    being_debugged = false;
86    return being_debugged;
87  }
88
89  // This process is being debugged if the P_TRACED flag is set.
90  is_set = true;
91  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
92  return being_debugged;
93}
94
95#elif defined(OS_LINUX)
96
97// We can look in /proc/self/status for TracerPid.  We are likely used in crash
98// handling, so we are careful not to use the heap or have side effects.
99// Another option that is common is to try to ptrace yourself, but then we
100// can't detach without forking(), and that's not so great.
101// static
102bool BeingDebugged() {
103  int status_fd = open("/proc/self/status", O_RDONLY);
104  if (status_fd == -1)
105    return false;
106
107  // We assume our line will be in the first 1024 characters and that we can
108  // read this much all at once.  In practice this will generally be true.
109  // This simplifies and speeds up things considerably.
110  char buf[1024];
111
112  ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
113  if (HANDLE_EINTR(close(status_fd)) < 0)
114    return false;
115
116  if (num_read <= 0)
117    return false;
118
119  StringPiece status(buf, num_read);
120  StringPiece tracer("TracerPid:\t");
121
122  StringPiece::size_type pid_index = status.find(tracer);
123  if (pid_index == StringPiece::npos)
124    return false;
125
126  // Our pid is 0 without a debugger, assume this for any pid starting with 0.
127  pid_index += tracer.size();
128  return pid_index < status.size() && status[pid_index] != '0';
129}
130
131#elif defined(OS_NACL)
132
133bool BeingDebugged() {
134  NOTIMPLEMENTED();
135  return false;
136}
137
138#elif defined(OS_FREEBSD)
139
140bool DebugUtil::BeingDebugged() {
141  // TODO(benl): can we determine this under FreeBSD?
142  NOTIMPLEMENTED();
143  return false;
144}
145
146#endif  // defined(OS_FREEBSD)
147
148// We want to break into the debugger in Debug mode, and cause a crash dump in
149// Release mode. Breakpad behaves as follows:
150//
151// +-------+-----------------+-----------------+
152// | OS    | Dump on SIGTRAP | Dump on SIGABRT |
153// +-------+-----------------+-----------------+
154// | Linux |       N         |        Y        |
155// | Mac   |       Y         |        N        |
156// +-------+-----------------+-----------------+
157//
158// Thus we do the following:
159// Linux: Debug mode, send SIGTRAP; Release mode, send SIGABRT.
160// Mac: Always send SIGTRAP.
161
162#if defined(NDEBUG) && !defined(OS_MACOSX)
163#define DEBUG_BREAK() abort()
164#elif defined(OS_NACL)
165// The NaCl verifier doesn't let use use int3.  For now, we call abort().  We
166// should ask for advice from some NaCl experts about the optimum thing here.
167// http://code.google.com/p/nativeclient/issues/detail?id=645
168#define DEBUG_BREAK() abort()
169#elif defined(ARCH_CPU_ARM_FAMILY)
170#define DEBUG_BREAK() asm("bkpt 0")
171#else
172#define DEBUG_BREAK() asm("int3")
173#endif
174
175void BreakDebugger() {
176  DEBUG_BREAK();
177}
178
179}  // namespace debug
180}  // namespace base
181