Подтвердить что ты не робот

Обнаружение, если приложение iOS запущено в отладчике

Я настроил свое приложение для отправки вывода отладки на консоль или в файл журнала. Теперь я хотел бы решить, в коде,

  • он запускается в отладчике (или симуляторе) и имеет, таким образом, консольное окно, в котором я хотел бы напрямую прочитать результат или если
  • нет окна консоли и, следовательно, вывод должен быть перенаправлен в файл.

Есть ли способ определить, работает ли приложение в отладчике?

4b9b3361

Ответ 1

Там есть функция от Apple, чтобы определить, отлаживается ли программа в записи Технического Q & A 1361 (в библиотеке Mac и в библиотеке iOS, они идентичны).

Код из Технического 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 );
}

Также обратите внимание на это примечание в конце Q & A:

Важно:. Поскольку определение структуры kinfo_proc<sys/sysctl.h>) обусловлено __APPLE_API_UNSTABLE, вы должны ограничить использование приведенного выше кода в сборке отладки вашей программы.

Ответ 2

Можно дать отладчику команду установить переменные среды при запуске процесса, который он собирается отлаживать. Это можно сделать в Xcode, перейдя в пункт меню Product-> Редактировать схему. Затем на вкладке Аргументы схемы отладки добавьте новую переменную среды. Переменная должна иметь имя "отладчик" со значением "true". Затем можно использовать следующий фрагмент кода, чтобы определить, запустил ли отладчик ваш процесс:

NSDictionary* env = [NSProcessInfo processInfo].environment;

if ([env[@"debugger"] isEqual:@"true"]) {
    NSLog(@"debugger yes");
}
else {
    NSLog(@"debugger no");
}

Ответ 3

Всегда хорошо иметь разные решения, поэтому вот мои два цента:

Идея состоит в том, чтобы проверить дескриптор файла stderr (там, где NSLog печатает). Это решение надежно работает с по крайней мере iOS 4 и продолжает делать это в iOS 9, как на симуляторе, так и на устройстве.

#import <sys/ioctl.h>
#import <sys/param.h>
#if TARGET_IPHONE_SIMULATOR
    #import <sys/conf.h>
#else
// Not sure why <sys/conf.h> is missing on the iPhoneOS.platform.
// It there on iPhoneSimulator.platform, though. We need it for D_DISK, only:
    #if ! defined(D_DISK)
        #define D_DISK  2
    #endif
#endif

BOOL isDebuggerAttatchedToConsole(void)
{
    // We use the type of the stderr file descriptor
    // to guess if a debugger is attached.

    int fd = STDERR_FILENO;

    // is the file handle open?
    if (fcntl(fd, F_GETFD, 0) < 0) {
        return NO;
    }

    // get the path of stderr file handle
    char buf[MAXPATHLEN + 1];
    if (fcntl(fd, F_GETPATH, buf ) >= 0) {
        if (strcmp(buf, "/dev/null") == 0)
            return NO;
        if (strncmp(buf, "/dev/tty", 8) == 0)
            return YES;
    }

    // On the device, without attached Xcode, the type is D_DISK (otherwise it D_TTY)
    int type;
    if (ioctl(fd, FIODTYPE, &type) < 0) {
        return NO;
    }

    return type != D_DISK;
}

Ответ 4

Самое простое решение на самом деле -

_isDebugging = isatty(STDERR_FILENO);

Это не совсем то же самое, что сказать, работает ли приложение под отладчиком, но достаточно хорошо (даже лучше?), чтобы определить, должен ли журнал записываться на диск.

Ответ 5

Для меня этот фрагмент быстрого кода отлично работает:

func isDebuggerAttached() -> Bool {
    return getppid() != 1
}

Ответ 6

Я обычно выбираю гораздо более простое решение; это бинарный файл с оптимизацией?

Отладочная сборка не оптимизирована, а журналы хороши. У сборки релизов должна быть оптимизация и не так много журналов. Вы можете проверить это с помощью символа __OPTIMIZE__.

Для ведения журнала я использую эту настройку для logg-функций:

#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__] )

Ответ 7

Основанный на ответе в дублирующем потоке, который был также для Objective-C и показал, как это делает HockeyApp-iOS, вот версия Swift 5:

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
}()

Ответ 8

Почему бы не использовать блок условной компиляции в Swift?

     #if DEBUG
        // Do something.
     #endif

Есть возражения?

Вы можете определить, хотите ли вы постоянную времени выполнения

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

Тот же подход может быть использован в Objc & more.