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