在没有符号的设备上调试 iOS 应用程序

Posted

技术标签:

【中文标题】在没有符号的设备上调试 iOS 应用程序【英文标题】:Debug iOS application on device without symbols 【发布时间】:2012-06-02 09:12:32 【问题描述】:

我需要在实际设备上调试 ios 应用程序的启动...并且启动是指当操作系统将控制权交给应用程序时执行的第一条指令 .不是“主要”。此外,此应用程序没有任何符号(即调试信息不​​可用.. 尚未)。我不在乎是否必须在 CPU 指令级别进行调试。我知道该怎么做(做了 30 多年)。当控制权即将转移到应用程序时,我希望调试器 stop。当我使用 Attach|by Name 命令并运行时,它只会显示“已完成运行”。

哦,这个应用程序不是在 XCode 中构建的,但是我构建、签名和配置并移动到设备的应用程序。该应用程序确实运行,因为我可以看到控制台输出。以防你认为我是试图调试某人应用程序的黑客。

这对于一个高要求来说怎么样?我敢打赌没有人能回答这个问题......我无法找到任何关于如何使用 XCode 构建的项目来做到这一点的信息。我想知道这是否根本不可能或被苹果霸主“允许”?

你说什么,堆栈溢出之神?

更新:我应该澄清一些事情。此应用程序不是使用任何商用或开源工具构建的。我与创建编译器、框架和 IDE 的工具供应商合作。 IOW,你不能得到这个工具......但是。在引导新工具链的过程中,必须定期进行一些非常低级的原始调试。特别是如果工具生成的代码中存在错误。

【问题讨论】:

如果是这样的话,这只是苹果作为开发者工具敌对的另一个例子。即使是 MS 在其最反竞争的年代也从未如此敌对。 我对内核只字未提。这是纯粹的用户空间调试。我只是在询问如何让调试器在控制转移到应用程序后停止,并添加皱纹,即没有符号和/或行号信息。 您确实需要更好地解释您正在尝试做什么,以及您希望通过尽早开始调试来找到什么。你看到崩溃了吗?您的程序是否有一些您不理解的初始启动状态?整个问题看起来就像你把问题弄得比它需要的复杂得多。 嗯,我确实解释过我与一家编程工具供应商合作,这意味着大多数人认为理所当然的东西我没有。大多数人的编译器、调试器、IDE 已经完成并准备就绪。我正在创建这些东西的过程中,并且需要能够引导该过程,以便客户可以理所当然地认为他们是工具,并且它的供应商已经经历了痛苦让事情顺利进行。 Allen - 微软的黑暗时刻非常黑暗,但至少我们可以依靠 Periscope CPU 分线开关。 (冻结!好吧,没人动。我们在哪里?)还记得在 16 位 Windows 可执行文件的启动代码中摆弄的无证堆栈吗?在微软承认运行应用程序需要魔术舞之前,我们已经进行了很长时间的逆向工程,甚至在他们解释为什么需要之前更长时间。 p.s.祝你最新的谜题好运! :> 【参考方案1】:

我将回答我自己的问题,因为我想我偶然发现了一个解决方案。如果有人有比这更优雅和简单的东西,也请回答。步骤:

从原始的整体 iOS 可执行文件开始(不是捆绑的 .app,而是作为机器代码的实际二进制 mach-o 文件)。

    创建一个新的同名空 Xcode 项目。在设备上构建并运行它。 找到输出包的 .app 文件夹。 将上述原始 iOS 可执行文件复制到 .app 包文件夹中的现有可执行文件上。 应用程序现在将具有无效签名,无法部署和运行。 针对应用程序包运行 codesign(您可以通过在上述 Xcode 项目上运行 xcodebuild 来找到命令行)。 在包的 .app 文件夹中,对二进制映像运行 otool -h -l。找到 LC_UNIXTHREAD 加载命令并找到与“pc”寄存器关联的值。这是操作系统加载程序将跳转到您的应用程序的地址。如果这个地址是奇数,那么这些是 Thumb 指令,否则它将是 ARM(我认为它是这样工作的)。 添加符号断点(我使用 GDB 而不是 LLDB)并输入地址为 '*0x00001234' 作为符号。 选择产品|执行操作|在不构建的情况下运行。

假设 GDB 能够计算断点表达式并设置断点,并且您选择了产品|调试工作流|调试时显示反汇编,该进程应该在应用程序中执行的第一条指令处中断。

您现在可以单步执行指令并使用 GDB 控制台获取/设置寄存器值。

【讨论】:

这有点偏离主题,但它与您关于使用 GDB 代替 LLDB 的观点有关。在模拟器上使用 LLDB 和调试应用程序时,“模块视图”完全是空白的。如果你想知道你的应用程序内存中有哪些系统动态库,你不能!?解决方法是将项目配置为使用 GDB,但更改项目配置会导致 Xcode 发出新警告。 很高兴您找到了答案,我以为我在其他回复中提到了 otool,但发现它被拼写更正为“工具”。也很高兴了解将您指向条目的 LC_UNIXTHREAD 命令... @Mark:我会就此提交一份雷达文件,或者与 WWDC 的 XCode 人员交谈。【参考方案2】:

您的问题没有意义 - main 是应用程序的入口点。这是应该遇到的第一个代码,除非您可能已经为某些类重写了 initialize()(但即便如此,我认为 main 会在运行时之前被命中)。

我认为您在启动时看到了某种奇怪的错误,并且您认为您想在入口处设置一个断点来捕获它,但更有可能帮助您的是在启动时描述问题并让其中一个4000 人看到并修复了相同的崩溃帮助您...

但是,如果您真的想使用 GDB 来中断没有符号的应用程序(但是您从 XCode 启动),您可以按照以下方式在程序集地址上使用 GDB 中断:

How to break on assembly instruction at a given address in gdb?

要查找main(或其他方法)的地址,您可以使用工具或atos,此问题中的一些示例:

Matching up offsets in iOS crash dump to disassembled binary

补充:

如果由于某种原因 XCode 无法启动您的应用程序进行调试,您也可以越狱并在设备本身上安装 GDB,这样可以完全控制调试。如果 XCode 可以启动您的应用程序,我看不出为什么能够在任意内存地址处中断不会给您所寻求的能力......

【讨论】:

呃.. "main" 不是实际的入口点。它是从包含入口点的实际“启动”代码中调用的。 我认为应用程序是由某些工具生成的整个机器代码字节(在本例中为 ARM v7)。因此,“将控制权转移到应用程序”意味着“一旦 CPU 越过边界(通过 BL 或 BLX 指令)从操作系统到应用程序的第一条指令,如 mach-o 可执行二进制文件所定义的那样。 @Kendall,看看艾伦的个人资料,尤其是他的简历和他博客的链接。他有他的理由(顺便说一句,这真的不重要 - 无论你是否理解为什么要问这个问题,这个问题都是有效的:-))。 谢谢,肯 ;-)。我故意对原因含糊其辞,是的。但是,我试图在最基本的层面上明确我的要求。对于那些不从事创建 编程工具(编译器、调试器、IDE 等)业务的人来说,我清楚地知道这一点,他们并没有真正考虑过从无到有所带来的痛苦。大多数人只是想当然地认为编程工具“就在那里”。 在一个致力于帮助人们的问答网站上,我只想回答没有被问到的问题——任何问题的重点都是解决问题。在不知道问题的情况下,很容易认为您可能问错了问题,就像许多其他人以前一样。我的声誉积分不是通过魅力或美貌获得的,而是通过帮助他人和解决问题来获得的,而这并不总是通过回答所提出的确切问题来获得。您的添加确实提供了提供真实答案所需的说明,尽管基本上我添加的越狱附录应该对您有所帮助。【参考方案3】:

对于具有 webviews 的应用程序的一种解决方案是在 iOS 模拟器中运行它们,并使用 macOS Safari 中的远程调试器连接到该模拟器。这是题外话,但也许其中一个或另一个可能会受益。

http://hiediutley.com/2011/11/22/debugging-ios-apps-using-safari-web-inspector/

或者在 iOS 上使用 NetCat...不是最完美的解决方案,但至少你可以看到发生了什么。

【讨论】:

以上是关于在没有符号的设备上调试 iOS 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在同一台 Mac 上调试两个 iOS 设备?

没有存档的 Xcode 符号

我可以在设备上调试我的 iOS 应用程序而不将其添加到 Apple 配置门户吗?

如何在具有较高 iOS 的设备上调试具有较低 SDK 的 iOS 应用程序构建

BusyBox 上没有调试符号交叉编译 ARM

如何在 ios 设备上未启动本机应用程序时进行调试