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