【问题标题】:Can I have an iOS process await a debugger?我可以让 iOS 进程等待调试器吗?
【发布时间】:2018-07-31 16:33:38
【问题描述】:

在测试我的 iOS 应用时,我的代码有时会遇到意外情况(精简断言失败),它会向我显示警报,让我知道发生问题的文件和行。

但是,到目前为止,我已经超越了“断言”失败的实际点,所以即使我将 LLDB 附加到进程,也没什么可看的。

有没有办法暂停 iOS 进程,直到我连接了调试器,所以 LLDB 将在故障点正常运行,可以访问调用堆栈、变量等?我不希望应用程序崩溃,就像使用简单的断言一样。

【问题讨论】:

  • 在什么意义上,应用程序“已经超过了‘断言’失败的实际点”?它不是还在assert() 调用(或等效)中吗?你能不只是走上堆栈(在调试器中)查看该调用的上下文吗?我的意思是,如果你可以暂停并等待调试器,那不就和你的警报代码在同一个上下文中了吗?

标签: ios xcode lldb


【解决方案1】:

通常这很容易——在你的程序中添加一个busyloop。在 C 语言中,您可能有一个静态文件,例如

static int wait_for_debugger = 1;

然后在你有你的软断言的时候,

if (bad_condition)
{
    while (wait_for_debugger)
        sleep (1);
}

当您在应用程序中遇到该条件时,线程将在此时永远等待,直到您附加调试器并执行类似的操作

(lldb) e wait_for_debugger = 0

我在 iOS 应用中看到的复杂情况是,如果您的应用停止响应事件,SpringBoard 会注意到并认为您的应用已挂起并将其终止。如果你在主线程上的事件循环仍在执行你会没事的,但是让另一个线程坐在这个busyloop中可能会导致其他问题。当调试器附加到 iOS 进程时,SpringBoard 知道应用程序停止响应事件是可以的(例如,您可能会在断点处停止)但如果它是免费运行的,我看不到它工作.

另一种选择是一直将调试器附加到应用程序,直到您重现故障 - 但我假设它只是偶尔发生?因此,每次从 Xcode 启动它(或从 Xcode 附加到它)可能需要额外的工作,直到您回购失败为止。另一方面,如果您可以使用“始终在调试器下运行”模型,则可以在软断言上使用断点。

【讨论】:

  • 正确 - 这个问题只是偶尔发生,所以我并不总是附加 Xcode。可靠的无线调试使这变得更容易一些,但我仍然无法始终运行调试器。
  • 您需要将wait_for_debugger 设为volatile,否则编译器可以优化读取它。
  • 嗯,在 -O0 我希望编译器保留符号,因为它实际上在函数中使用,尽管我可以看到编译器将其设为 const 值,因为它从未被修改和使用循环中的常量。在这种情况下,删除 static 存储限定符可能会使编译器保持诚实;编译器很难知道它没有在其他地方修改。
【解决方案2】:

这不是一个实际的答案。我很抱歉,但探索太有趣了,不能分享,太长不能发表评论,我很想看到有人以此为基础。

我首先设置要调试的应用程序 (PT_TRACE_ME),然后触发断点 (SIGTRAP)。这只是从 Swift 中的按钮 IBAction 调用的。

#include "debug.h"
#import <dlfcn.h>
#import <sys/types.h>
#include <signal.h>

typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);

void debugme() {
    void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
    ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
    ptrace_ptr(0, 0, 0, 0);
    dlclose(handle);
    kill(0, SIGTRAP);
}

(我确信这会禁止您进入应用商店。我绝不会将其包含在运输应用的生产版本中。)

所以接近工作了(如果你已经在 Xcode 下运行,发送你自己SIGTRAP 确实有效,但在这种情况下你可以设置一个断点)。它挂起程序,程序不会因为未能处理其运行循环而被终止,并且它作为可能的目标显示在“调试,附加到进程”列表中。但是,当您尝试实际连接时,Xcode 抱怨它无法连接到它。在你得到的 iOS 日志中:

default 16:10:52.889240 -0400   debugserver error: Attach failed: "(os/kern) invalid task".

这可能不足为奇,因为应用的父级并不期望它被调试。所以也许这表明这确实是不可能的。

所以,好吧,它失败了。但这就是它变得有点奇怪的地方:

这个应用程序不会死。我的意思是强制杀死不会杀死这个应用程序。它仍然显示在 Xcode 的进程列表中。主页按钮会将您带到跳板,如果您重新启动应用程序,您只会得到一个白屏(我猜是因为它甚至无法重新绘制自己?)

当应用程序在前台时屏幕锁定时,主页按钮不再起作用以将其唤醒。 power 按钮不再起作用。按住电源关机最终给出了触觉脉冲,但没有关闭手机。我必须进行重置(电源+家庭)才能重新启动。我很惊讶我可以从沙盒用户态进程中如此艰难地锁定手机。

所以也许这不是最好的方法,但感觉与实际答案非常接近,我还是想分享它。

【讨论】:

    猜你喜欢
    • 2010-10-20
    • 2015-05-16
    • 2015-06-30
    • 2016-03-09
    • 2018-12-14
    • 2020-12-27
    • 2015-10-27
    • 2020-02-23
    • 2020-03-02
    相关资源
    最近更新 更多