官方文档,Understanding and Analyzing Application Crash Reports
前言
当app发生crash时,系统会生成crash report并存储在设备上.
Crash Report
, 尤其是堆栈信息,在被符号化之前是不可读的。所谓符号化就是把内存地址用可读的函数名和行数来替换。 注意使用 .crash文件Low Memory Report
它没有堆栈信息
符号化
编译代码的时候,通过build setting里的Debug Information Format(DEBUG_INFORMATION_FORMAT)
临时介绍一下:
- 关于DWARF与dSYM
- DWARF与dSYM的关系是,DWARF是文件格式,而dSYM往往指一个单独的文件。在Xcode中如果不做特殊制定,debug information是被保存在executable文件中,可以使用dsymutil从executable中提取dSYM文件。
- dsymutil
- dsymutil is a tool to manipulate archived DWARF debug symbol files. 使用dsymutil可以对dSYM文件进行如下操作:从exe_path中提取成dSYM文件、将executable或者object文件中的symbol table dump出来、更新dSYM文件以让dSYM文件包含最新的accelerator tables and other DWARF optimizations。
- Debug Info Format
- 在Xcode中可以选择DWARF和DWARF with dSYM file,推荐的设置是Debug用DWARF;Release使用DWARF with dSYM file。
- 使用dSYM file
- 如果我们有若干的build,有若干dSYM文件,而名字又有点乱,想知道哪个dSYM跟哪个build匹配,从而可以使用它们呢?办法就是查看UUID。
- 一般来说,debug模式构建的app会把Debug符号表存储在编译好的binary信息中,而release模式构建的app会把debug符号表存储在dSYM文件中以节省体积。
同一次构建,app+dSYM+UUID是一套的。如果这几个文件不属于同一次构建,即便是相同的源代码,互相之间在符号化这个事情上也无法互相工作。
- 你为了分发app而选择Archive(存档)时,Xcode会把app的二进制信息和.dYSM文件存储在你的home文件夹下的某个地方。你可以在Xcode的Organizer里面通过”Archived”选项找到所有你存档过的app。
注意:想要解析来自于测试、app review或者客户的crash report,你需要保留分发出去的那些构建过的archive文件。
如果你是通过App Store分发app或者是Test Flight分发的beta版本的app,你将在上传archive到ITC(iTunes Connect)时看见一个“是否将dSYM一起上传”的选项。在上传对话框中,请勾选”在app中包含app符号表”。上传你的dYSM文件对于从TestFlight用户和客户以及愿意分享诊断信息的客户那边接收crash report是很有必要的。
注意:接收自App Review的crash report是不会被符号化的,及时你再上传你的app到ITC时勾选了包含dSYM文件。任何来自于App Review的crash report都需要在Xcode里做符号化。
当你的app 发生crash时,一个没有被符号化的crash report会被创建并存储在设备上。
用户可以通过调试已部署的iOS APP里提到的方法来直接从他们的设备里获得crash report。如果你通过AdHoc或者企业证书分发app,这是你唯一能从用户获取crash report的方法。
从设备上直接获取的crash report是没有被符号化的,你需要通过Xcode来符号化。Xcode会结合dSYM文件和你app的二进制信息把堆栈里的每一个地址对应到源代码中。处理后的结果就是一个符号化过的crash report。
如果用户愿意和Apple共享诊断信息,或者用户通过TestFlight下载了你的beta版本app,那crash report会被上传到App Store。
App Store在符号化crash report后会把内部所有的crash reports做汇总并分组,这种聚合(相似crash report)的方法叫做crash聚类。
这些符号化后的crash report可以在你的Xcode的Crash Organizer中进行查看。
Bitcode
Bitcode(位编码)是一个编译好的项目的中间表现形式。当你在允许bitcode的前提下Archive一个app时,编译器会在二进制中包含bitcode而不是机器码。一旦binary信息被上传到App Store中,bitcode会被再次编译成机器码。也许App Store会在将来二次编译bitcode
虽然当你Archive你的app时会创建dSYM文件,但它们只能用在bitcode binary信息中,并不能用于符号化crash report。 App Store允许你从Xcode或者ITC网站中下载这些随着bitcode编译而产生的dSYM文件。 为了解析从App Review或者给你发送crash report的用户的crash report,你必须要下载这些dSYM文件,这样才能符号化crash report。 如果是从crash reporting service那里接收crash report,符号化会自动完成。
意思就是说,选择了Bitcode,你得从AppStore下载dSYM, 才是真正和binary信息匹配的,而不是你的中间码(提交的原始文件)
把”隐藏的”符号名还原成原始名
你把一个带有bitcode的app上传到App Store时,你也许在提交对话框中并没有勾选“上传你的app的符号表信息以便从Apple那边接收符号化过的 report”的选项。 当你选择不发送符号表信息给Apple时,Xcode会在你发送app到ITC之前用晦涩难懂的符号例如”_hidden#109”等来替换你的app里的dSYM文件。Xcode会创建一个原始符号和”隐藏”符号的对照表,并且将其存储在Archive的app文件中的一个bcsymbolmap文件里。每一个dSYM文件都会有一个对应的bcsymbolmap文件。
在符号化crash report之前,你需要把那些从ITC中下载下来的dSYM文件中的晦涩信息给解析一下。 如果你使用Xcode中的下载dSYM按钮,这步解析会自动完成。但是,如果你通过ITC网站来下载dSYM的话,你需要打开Terminal并且手动输入下面的命令来做解析(把example的path信息和sSYM信息替换一下)
xcrun dsymutil -symbol-map ~/Library/Developer/Xcode/Archives/2017-11-23/MyGreatApp\ 11-23-17,\ 12.00\ PM.xcarchive/BCSymbolMaps ~/Downloads/dSYMs/3B15C133-88AA-35B0-B8BA-84AF76826CE0.dSYM
针对每一个dSYMs文件夹下的dSYM文件都运行一次这条命令。
用Xcode符号化iOS的Crash report
一般来说,Xcode会自动尝试符号化它所有的Crash report。所以你只需要把crash report加到Xcode Organizer就可以了。Note
:Xcode只认.crash后缀的crash report。如果你收到的crash report没有后缀名或者后缀是txt,在执行下列步骤之前先把它改成.crash。
- 把iOS设备连接到你的Mac
- 从Window菜单栏选择Devices
- 在Devices左侧,选择一个设备
- 点击右边在“Device Information“ 下面的 ”View Device Logs” 按钮
- 把你的Crash report拖拽到左侧panel中
- Xcode会自动符号化Crash report并且显示结果
为了符号化一个Crash report,Xcode需要去定位如下信息:
- 崩溃的app的binary信息以及dSYM文件
- 所有app关联的自定义framework的binary信息以及dSYM文件。如果是从app构建出来的framework,它们的dYSM会随着app的dSYM文件一起拷贝到archive中。如果是第三方的framework,你需要去找作者要dYSM文件。
- 发生crash时app所依赖的OS的符号表信息。这些符号表包含了特定OS版本(例如iOS9.3.3)上的framework所需调试信息。 OS 符号表的架构具有独特性——一个64位的iOS设备不会包含armv7的符号表。Xcode将要自动拷贝你连接到的特定版本的Mac的符号表。
在上述任何一处,如果没有Xcode,你将无法符号化一个crash report,或者只能部分符号化一个crash report。
用atos符号化Crash report
atos
命令可以把地址里的数字替换成等价的符号。如果调试符号信息是完备的,则atos的输出信息将会包含文件名和对应的资源行数。atos命令可以被用来单独符号化那些未符号化或者部分符号化过的crash report(中的堆栈信息里的地址)。
想要使用atos符号化crash report可以按如下方式操作:
- 找到你想要符号化的那一行,记下第二列的binary信息名,以及第三列的地址。
- 从crash report底部的binary信息名列表中找到那个名字,记下来架构名和加载的地址。
atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>
使用atos命令的样例,以及结果输出
$ atos -arch arm64 -o TheElements.app.dSYM/Contents/Resources/DWARF/TheElements -l 0x1000e4000 0x00000001000effdc
-[AtomicElementViewController myTransitionDidStop:finished:context:]
利用符号化排查问题
xcrun dwarfdump –uuid
注意:你必须保存你最开始上传到App Store的发生crash的app的归档文件。dSYM文件和app二进制文件是一一对应,且每次构建都不相同。即便通过相同的源码和配置,再执行一次构建,生成的dSYM文件也无法和之前的crash report做符号化匹配。
如果你不在存有这个归档文件,你应该重新提交一次有归档的新版本,以确保再发生crash的时候你可以符号化crash report。