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