1 /* 2 * Created by Phil on 27/12/2010. 3 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 * 8 */ 9 #ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED 10 #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED 11 12 #include "catch_debugger.h" 13 #include "catch_errno_guard.hpp" 14 15 #ifdef CATCH_PLATFORM_MAC 16 17 #include <assert.h> 18 #include <stdbool.h> 19 #include <sys/types.h> 20 #include <unistd.h> 21 #include <sys/sysctl.h> 22 23 namespace Catch{ 24 25 // The following function is taken directly from the following technical note: 26 // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html 27 28 // Returns true if the current process is being debugged (either 29 // running under the debugger or has a debugger attached post facto). isDebuggerActive()30 bool isDebuggerActive(){ 31 32 int mib[4]; 33 struct kinfo_proc info; 34 size_t size; 35 36 // Initialize the flags so that, if sysctl fails for some bizarre 37 // reason, we get a predictable result. 38 39 info.kp_proc.p_flag = 0; 40 41 // Initialize mib, which tells sysctl the info we want, in this case 42 // we're looking for information about a specific process ID. 43 44 mib[0] = CTL_KERN; 45 mib[1] = KERN_PROC; 46 mib[2] = KERN_PROC_PID; 47 mib[3] = getpid(); 48 49 // Call sysctl. 50 51 size = sizeof(info); 52 if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { 53 Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; 54 return false; 55 } 56 57 // We're being debugged if the P_TRACED flag is set. 58 59 return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); 60 } 61 } // namespace Catch 62 63 #elif defined(CATCH_PLATFORM_LINUX) 64 #include <fstream> 65 #include <string> 66 67 namespace Catch{ 68 // The standard POSIX way of detecting a debugger is to attempt to 69 // ptrace() the process, but this needs to be done from a child and not 70 // this process itself to still allow attaching to this process later 71 // if wanted, so is rather heavy. Under Linux we have the PID of the 72 // "debugger" (which doesn't need to be gdb, of course, it could also 73 // be strace, for example) in /proc/$PID/status, so just get it from 74 // there instead. isDebuggerActive()75 bool isDebuggerActive(){ 76 // Libstdc++ has a bug, where std::ifstream sets errno to 0 77 // This way our users can properly assert over errno values 78 ErrnoGuard guard; 79 std::ifstream in("/proc/self/status"); 80 for( std::string line; std::getline(in, line); ) { 81 static const int PREFIX_LEN = 11; 82 if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { 83 // We're traced if the PID is not 0 and no other PID starts 84 // with 0 digit, so it's enough to check for just a single 85 // character. 86 return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; 87 } 88 } 89 90 return false; 91 } 92 } // namespace Catch 93 #elif defined(_MSC_VER) 94 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 95 namespace Catch { isDebuggerActive()96 bool isDebuggerActive() { 97 return IsDebuggerPresent() != 0; 98 } 99 } 100 #elif defined(__MINGW32__) 101 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 102 namespace Catch { isDebuggerActive()103 bool isDebuggerActive() { 104 return IsDebuggerPresent() != 0; 105 } 106 } 107 #else 108 namespace Catch { isDebuggerActive()109 inline bool isDebuggerActive() { return false; } 110 } 111 #endif // Platform 112 113 #ifdef CATCH_PLATFORM_WINDOWS 114 115 #include "catch_windows_h_proxy.h" 116 117 namespace Catch { writeToDebugConsole(std::string const & text)118 void writeToDebugConsole( std::string const& text ) { 119 ::OutputDebugStringA( text.c_str() ); 120 } 121 } 122 #else 123 namespace Catch { writeToDebugConsole(std::string const & text)124 void writeToDebugConsole( std::string const& text ) { 125 // !TBD: Need a version for Mac/ XCode and other IDEs 126 Catch::cout() << text; 127 } 128 } 129 #endif // Platform 130 131 #endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED 132