catch_debugger.cpp 4.3 KB

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