Detecting if iOS app is run in debugger

前端 未结 8 1707
北恋
北恋 2020-11-27 13:45

I set up my application to either send debugging output to console or a log file. Now, I\'d like to decide with in the code whether

  • it is run in the debugger
相关标签:
8条回答
  • 2020-11-27 13:58

    There's a function from Apple to detect whether a program is being debugged in the Technical Q&A 1361 (entry in Mac library and entry in iOS library; they are identical).

    Code from the Technical Q&A:

    #include <assert.h>
    #include <stdbool.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/sysctl.h>
    
    static bool AmIBeingDebugged(void)
        // Returns true if the current process is being debugged (either 
        // running under the debugger or has a debugger attached post facto).
    {
        int                 junk;
        int                 mib[4];
        struct kinfo_proc   info;
        size_t              size;
    
        // Initialize the flags so that, if sysctl fails for some bizarre 
        // reason, we get a predictable result.
    
        info.kp_proc.p_flag = 0;
    
        // Initialize mib, which tells sysctl the info we want, in this case
        // we're looking for information about a specific process ID.
    
        mib[0] = CTL_KERN;
        mib[1] = KERN_PROC;
        mib[2] = KERN_PROC_PID;
        mib[3] = getpid();
    
        // Call sysctl.
    
        size = sizeof(info);
        junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
        assert(junk == 0);
    
        // We're being debugged if the P_TRACED flag is set.
    
        return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
    }
    

    Also pay attention to this note at the end of the Q&A:

    Important: Because the definition of the kinfo_proc structure (in <sys/sysctl.h>) is conditionalized by __APPLE_API_UNSTABLE, you should restrict use of the above code to the debug build of your program.

    0 讨论(0)
  • 2020-11-27 14:01

    It is possible to instruct the debugger to set environment variables when it launches a process it is about to debug. This can be done in Xcode by going to the menu item Product->Edit Scheme. Then under the Debug scheme's Arguments tab add a new environment variable. The variable should be named "debugger" with the value "true". Then the following code snippet can be used to determine if the debugger launched your process:

    NSDictionary* env = [NSProcessInfo processInfo].environment;
    
    if ([env[@"debugger"] isEqual:@"true"]) {
        NSLog(@"debugger yes");
    }
    else {
        NSLog(@"debugger no");
    }
    
    0 讨论(0)
  • 2020-11-27 14:02

    Why not using conditional compilation block in Swift?

         #if DEBUG
            // Do something.
         #endif
    

    Any objection?

    You can define if you want a runtime constant

    #if DEBUG
    public let IS_RUNNING_IN_DEBUGGER: Bool = true
    #else
    public let IS_RUNNING_IN_DEBUGGER: Bool = false
    #endif
    

    The same approach can be used in Objc & more.

    0 讨论(0)
  • 2020-11-27 14:03

    For me this piece of swift-code works perfectly:

    func isDebuggerAttached() -> Bool {
        return getppid() != 1
    }
    
    0 讨论(0)
  • 2020-11-27 14:03

    I usually go for a much more simple solution; is the binary compiled with optimizations?

    A debug build is not optimized, and logs are nice. A release build should have optimizations and not as many logs. You can check for this with the __OPTIMIZE__ symbol.

    For logging I use this setup for logg-functions:

    #ifdef __OPTIMIZE__ 
      #define CWLog(...)
      #define CWLogDebug(...)
      #define CWLogInfo(...)
    #else
      #define CWLog(...) NSLog(__VA_ARGS__)
      #define CWLogDebug( s, ... ) NSLog( @"DEBUG <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
      #ifndef LOG_INFO
        #define CWLogInfo(...)
      #else
        #define CWLogInfo( s, ... ) NSLog( @"INFO <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
      #endif
    #endif
    #define CWLogWarning( s, ... ) NSLog( @"WARNING <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    #define CWLogError( s, ... ) NSLog( @"ERROR <%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    
    0 讨论(0)
  • 2020-11-27 14:05

    Based off an answer in a duplicate thread that was for Objective-C as well and showed how HockeyApp-iOS does it, here's a Swift 5 version:

    let isDebuggerAttached: Bool = {
        var debuggerIsAttached = false
    
        var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
        var info: kinfo_proc = kinfo_proc()
        var info_size = MemoryLayout<kinfo_proc>.size
    
        let success = name.withUnsafeMutableBytes { (nameBytePtr: UnsafeMutableRawBufferPointer) -> Bool in
            guard let nameBytesBlindMemory = nameBytePtr.bindMemory(to: Int32.self).baseAddress else { return false }
            return -1 != sysctl(nameBytesBlindMemory, 4, &info/*UnsafeMutableRawPointer!*/, &info_size/*UnsafeMutablePointer<Int>!*/, nil, 0)
        }
    
        // The original HockeyApp code checks for this; you could just as well remove these lines:
        if !success {
            debuggerIsAttached = false
        }
    
        if !debuggerIsAttached && (info.kp_proc.p_flag & P_TRACED) != 0 {
            debuggerIsAttached = true
        }
    
        return debuggerIsAttached
    }()
    
    0 讨论(0)
提交回复
热议问题