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 10 #include "catch_debugger.h" 11 #include "catch_errno_guard.h" 12 #include "catch_stream.h" 13 #include "catch_platform.h" 14 15 #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) 16 17 # include <assert.h> 18 # include <stdbool.h> 19 # include <sys/types.h> 20 # include <unistd.h> 21 # include <cstddef> 22 # include <ostream> 23 24 #ifdef __apple_build_version__ 25 // These headers will only compile with AppleClang (XCode) 26 // For other compilers (Clang, GCC, ... ) we need to exclude them 27 # include <sys/sysctl.h> 28 #endif 29 30 namespace Catch { 31 #ifdef __apple_build_version__ 32 // The following function is taken directly from the following technical note: 33 // https://developer.apple.com/library/archive/qa/qa1361/_index.html 34 35 // Returns true if the current process is being debugged (either 36 // running under the debugger or has a debugger attached post facto). isDebuggerActive()37 bool isDebuggerActive(){ 38 int mib[4]; 39 struct kinfo_proc info; 40 std::size_t size; 41 42 // Initialize the flags so that, if sysctl fails for some bizarre 43 // reason, we get a predictable result. 44 45 info.kp_proc.p_flag = 0; 46 47 // Initialize mib, which tells sysctl the info we want, in this case 48 // we're looking for information about a specific process ID. 49 50 mib[0] = CTL_KERN; 51 mib[1] = KERN_PROC; 52 mib[2] = KERN_PROC_PID; 53 mib[3] = getpid(); 54 55 // Call sysctl. 56 57 size = sizeof(info); 58 if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { 59 Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; 60 return false; 61 } 62 63 // We're being debugged if the P_TRACED flag is set. 64 65 return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); 66 } 67 #else 68 bool isDebuggerActive() { 69 // We need to find another way to determine this for non-appleclang compilers on macOS 70 return false; 71 } 72 #endif 73 } // namespace Catch 74 75 #elif defined(CATCH_PLATFORM_LINUX) 76 #include <fstream> 77 #include <string> 78 79 namespace Catch{ 80 // The standard POSIX way of detecting a debugger is to attempt to 81 // ptrace() the process, but this needs to be done from a child and not 82 // this process itself to still allow attaching to this process later 83 // if wanted, so is rather heavy. Under Linux we have the PID of the 84 // "debugger" (which doesn't need to be gdb, of course, it could also 85 // be strace, for example) in /proc/$PID/status, so just get it from 86 // there instead. isDebuggerActive()87 bool isDebuggerActive(){ 88 // Libstdc++ has a bug, where std::ifstream sets errno to 0 89 // This way our users can properly assert over errno values 90 ErrnoGuard guard; 91 std::ifstream in("/proc/self/status"); 92 for( std::string line; std::getline(in, line); ) { 93 static const int PREFIX_LEN = 11; 94 if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { 95 // We're traced if the PID is not 0 and no other PID starts 96 // with 0 digit, so it's enough to check for just a single 97 // character. 98 return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; 99 } 100 } 101 102 return false; 103 } 104 } // namespace Catch 105 #elif defined(_MSC_VER) 106 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 107 namespace Catch { isDebuggerActive()108 bool isDebuggerActive() { 109 return IsDebuggerPresent() != 0; 110 } 111 } 112 #elif defined(__MINGW32__) 113 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 114 namespace Catch { isDebuggerActive()115 bool isDebuggerActive() { 116 return IsDebuggerPresent() != 0; 117 } 118 } 119 #else 120 namespace Catch { isDebuggerActive()121 bool isDebuggerActive() { return false; } 122 } 123 #endif // Platform 124