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