如何像 Crashlytics 和开源 PLCrashReporter 那样获得崩溃的线路和方法

Posted

技术标签:

【中文标题】如何像 Crashlytics 和开源 PLCrashReporter 那样获得崩溃的线路和方法【英文标题】:How to get the line of the crash and the method as Crashlytics does and also the open source PLCrashReporter 【发布时间】:2016-01-07 20:05:13 【问题描述】:

正如我所提到的,我正在尝试恢复崩溃的线路以及它发生的功能。

我需要提及的是,我已经尝试了 AppDelegate 中的下一个代码,但我得到了未符号化的堆栈和类以及抛出的错误:

NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

void uncaughtExceptionHandler(NSException *exception) 

    NSLog(@"Exception description - %@",[exception description]);
    NSLog(@"Exception name - %@", [exception name]);
    NSLog(@"Reason - %@", [exception reason]);
    NSLog(@"\n\n - %@", [exception callStackSymbols]);
    NSLog(@"\n\n - %@", [exception callStackReturnAddresses]);

但是通过使用这些我没有得到崩溃的行,因为我打算将它保存在 CoreData 中。

另外,我对 xcode 方法不感兴趣:“添加异常断点”或其他方法:XCode > Window > Devices > 查看设备上的崩溃日志、测试飞行方法或在应用程序中将其他框架实现为 Crashlytics。

我之所以提到这些,是因为我对通过代码完成的方式非常感兴趣。

还能够在制作应用存档时获取应用存档的 dsym,并使用使用 Bash 编写的 RunScript 将其上传到服务器。因此,如果需要达到崩溃线,我可以使用 dsym。

另外我知道下一个方法可以用来获取当前代码行:LINE和_FUNCTION__来获取函数名。

此外,如果您可以提供来自开源 PLCrashReporter 的代码示例,我会非常感激。

比你们都提前! :)

【问题讨论】:

【参考方案1】:

基本上有两种类型的崩溃:

    未捕获的异常,可以使用与您的代码类似的代码来捕获 基于信号的崩溃,可以使用信号处理程序(或 Mach 异常处理程序,但不会捕获所有信号)来捕获

然后捕获任何这些崩溃,您需要获取堆栈跟踪(所有线程的)。 [NSException callStackSymbols] 将为您提供一些符号(仅用于异常崩溃),对于许多操作系统符号,它只会显示 redacted,对于您的应用程序,如果您不从二进制文件中删除它们,它将提供一些符号。建议从二进制文件中去除符号以减小文件大小(很多),而且这些符号也永远不会提供文件名和行号。

因此,您需要从堆栈帧中获取以下信息:二进制、二进制 UUID、cpu 架构和内存地址。 [NSException callStackReturnAddresses] 会给你内存地址,但同样只针对基于异常的崩溃。另外它不提供内存地址对应的二进制图像。

因此,您需要获取包含每个二进制图像所涵盖的内存地址范围的二进制图像列表,并且还需要一种方法来获取线程的堆栈帧的内存地址,也可以用于非基于异常的崩溃。如果想了解这是怎么回事,基本上可以看一下所有 PLCrashReporters 代码,因为这是开源项目的目的,解释如此复杂的场景不在 *** 的范围内。阅读代码、文档并学习 :) 给你一个简短的要点:不要自己做,只需使用 PLCrashReporter。

现在要获取包括文件名和行号在内的符号,您需要使用发生崩溃报告的设备的相应操作系统版本和相应 CPU 架构的操作系统符号来符号化崩溃报告。您还需要从您的应用程序触发崩溃报告的确切二进制文件(和框架)中的符号 (dSYM) 包。每个二进制图像都有一个唯一的 UUID,并且您用来获取符号的符号文件对于相同的 CPU 架构需要具有相同的 UUID。

现在您需要运行工具atos 以从特定符号文件中获取特定内存地址的符号。以下堆栈溢出答案显示了如何做到这一点:https://***.com/a/13576028/474794

作为替代方案,您可以使用 Xcode 附带的 symbolicatecrash.pl 脚​​本并获取 Apple 标准格式的崩溃报告(PLCrashReporter 有一个转换工具可以从其更紧凑的报告中创建此类报告)。

【讨论】:

我刚刚集成了 PLCrashReporter,我对如何检索崩溃行(如果存在)感兴趣?提前谢谢你 PLCrashReporter 无法做到这一点。您需要按照我的描述对它生成的报告进行符号化。 你的意思是我应该使用:NSLog(@"Crashed with signal %@ (code %@, address=0x%" PRIx64 ")", report.signalInfo.name, report.signalInfo.code, report.signalInfo.address);还是我应该使用:NSString *humanReadable = [PLCrashReportTextFormatter stringValueForCrashReport:report withTextFormat:PLCrashReportTextFormatios]; NSLog(@"Report: %@", humanReadable) 您应该创建一个格式为文本的报告,并且可以使用 Apple perl 脚本或自定义脚本来处理以添加符号。您的第一个示例只写了一行,没有可以符号化的真正崩溃报告。第二个写了这样的报告。请使用 PLCrashReporter 邮件列表了解具体问题,并查看示例项目和文档:groups.google.com/forum/#!forum/plcrashreporter【参考方案2】:

您可以在日志中使用__PRETTY_FUNCTION__,这将为您提供函数的行、类和名称。

NSLog(@"%@", __PRETTY_FUNCTION__);

您可以使用您喜欢的任何其他信息填写日志的其余部分。

【讨论】:

如何添加?你能提供更多细节吗?我可以将它添加到:uncaughtExceptionHandler 中以供一般使用吗? 是的,但它返回调用它的函数和行,而不是应用程序崩溃的函数名称,我有兴趣使用它来查找函数的名称,而不用在我的应用程序中调用它代码 啊我现在明白了。为什么不查看 PLCrashReporter 的源代码,看看它是如何完成的呢?作者或 PLCrashReporter 还写了一篇有趣的帖子,说明为什么不建议使用异常捕获。 landonf.bikemonkey.org/code/objc/… 你能提供一些关于 PLCrashReporter 的实际指南吗?

以上是关于如何像 Crashlytics 和开源 PLCrashReporter 那样获得崩溃的线路和方法的主要内容,如果未能解决你的问题,请参考以下文章

Crashlytics从框架中的异常报告

如何安装 Fabric 和 Crashlytics

当 Crashlytics 捕获异常时应用程序崩溃

如何从 Fabric Crashlytics 迁移到 Firebase Crashlytics?

Crashlytics 在运行时未在 crashlytics.properties 中找到 API 密钥

Crashlytics - 如何删除构建/版本?