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