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