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