开发中经常遇到苹果反馈的崩溃报告,绝大部分都是没有经过符号化的报告,看起来一头雾水排查问题也不知道如何下手,经过详细翻阅苹果官方文档以及经过亲身实践后,整理出来分析未经符号化报告的几种方法,记录下来,方便自己方便他人~
重要提醒:如果项目中开启了bitcode模式,那么在分析线上崩溃的时候一定要去更新下自己的dSYM文件,因为开启bitcode发布的包,在你本机上编译之后的版本并不是最终发布给用户的版本,从你本机上传至APPStore之后,APPStore会再次编译该应用包,然后分发给用户,所以用户拿到的包跟你编译提交至APPStore的包并不一致,你也无法使用你编译产生的dSYM文件来符号化线上苹果返回给你的崩溃报告。
更新dSYM文件的地方在这里(截图来自苹果官方文档)我将创建一个测试的APP,用来模拟程序的崩溃,然后从手机端获取到未符号化的崩溃报告,然后我们将使用三种方法将未符号化的报告符号化来分析问题所在。
先看简单的引起崩溃的代码:
数组越界崩溃很简单的一个数组越界,在手机端运行之后导出未符号化的崩溃报告保存在电脑上,这个过程模拟我们从APPStore获取到崩溃报告之后保存下来的行为,切记保存的格式为xxx.crash 文件。
先看一下完全没有符号化的崩溃报告:
没有符号化的崩溃报告没有任何参考意义,只是一堆十六进制的地址名,所以我们需要使用和这个编译包对应的符号表来符号化出来一个有参考意义的崩溃报告。一共有三种方法,逐个尝试。
一、使用Xcode来符号化崩溃报告
使用Xcode自带的符号化功能进行符号化也是官方比较推荐的一种做法,会检索你本机上的所有可用的符号化表进行符号化,具体步骤如下:
复制苹果给的报错报告,可以直接在网页右键,保存为.carsh格式,然后直接拖动到手机端端deviceLog列表,进行符号化的操作,就可以看到部分内容被符号化,然后搜寻关键的信息排查问题。
手机连接Xcode, 打开手机端的报告列表
拖动我们创建好的crash文件进入列表
如果没有符号化的话直接右键重新符号化一下,然后查看就可以。
可以看到报错的方法名及崩溃原因:
二 使用命令行符号化崩溃报告
使用命令行和使用Xcode自带的符号化工具类似,我们演示一下如果操作。
使用命令行进行崩溃报告符号化需要以下四个文件:
- crash文件
- symbolicatecrash工具
- dSYM包
- APP安装包文件
我们一个一个来找,其实很简单。
首先建立一个空的文件夹,把我们导出来的未符号化的崩溃报告放进去,命名为TestCrash.crash。
1.crash文件
这个文件就是我们导出来的未符号化的崩溃报告TestCrash.crash,已经有了。
2.symbolicatecrash工具
这个工具的目录地址为:
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
使用命令行直接open /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/
然后把symbolicatecrash这个文件拷贝至我们准备的文件夹里就可以。
3.dSYM包和APP安装包文件
dSYM包和APP安装包文件在一个地方,我们看下如何查找。
首先我们使用命令行cd到我们建立的文件夹下,此时里面有两个文件
- 获取匹配使用的UUID
使用命令行
grep --after-context=1000 "Binary Images:" <Path to Crash Report> | grep <Binary Name>
来获取到我们需要的跟dSYM匹配的UDID,我的APP命名为TestCrash,使用示例如下:
grep --after-context=1000 "Binary Images:" TestCrash.crash | grep TestCrash
可以看到输出为:
其中的c9c5a77b053f35a7b136d0036ca74da3就是APP对应的UDID,接下来将这个小心的UDID格式化为全部大小的各位为8—4-4-4-12位的编码,如下:
C9C5A77B-053F-35A7-B136-D0036CA74DA3
- 查找对应dSYM文件的位置
然后我们使用命令mdfind来查找对应dSYM文件的位置:
mdfind "com_apple_xcode_dsym_uuids == <UUID>"
使用示例如下:
mdfind "com_apple_xcode_dsym_uuids == C9C5A77B-053F-35A7-B136-D0036CA74DA3"
可以看到输出了dSYM文件的地址,然后我们open到这个地址,可以看到:
我们需要的dSYM包和APP安装包文件就是这两个了
(这种方式找到的dSYM包精准度比较高,还有比较简单的方式在文末会介绍,这种使用简单的方式介绍找到的包也一定要记得验证UUID)
把他们也全部拷贝到我们建立的文件夹里。
此时我们需要的四个文件全部都有了,我们建立的文件夹里的文件如下:
在进行最后一步前,我们先验证一下这几个文件的UUID是否匹配,如果不匹配的话我们符号化出来的报告是没有意义的。
重新cd到我们建立的文件夹里:
- 获取dSYM的UDID:
执行命令格式如下:
dwarfdump --uuid <PathToDSYMFile>/Contents/Resources/DWARF/<BinaryName>
使用示例如下:
dwarfdump --uuid TestCrash.app.dSYM/Contents/Resources/DWARF/TestCrash
结果如下:
可以看到,dSYM的UUID为:C9C5A77B-053F-35A7-B136-D0036CA74DA3
- 获取APP文件的UDID:
执行命令格式如下:
dwarfdump --uuid <PathToBinary>
使用示例如下:
dwarfdump --uuid TestCrash.app/TestCrash
结果如下:
可以看到,APP文件的UDID为:C9C5A77B-053F-35A7-B136-D0036CA74DA3
所以:
我们最开始从crash文件里获取到的UDID为:C9C5A77B-053F-35A7-B136-D0036CA74DA3
dSYM文件里的UDID为:C9C5A77B-053F-35A7-B136-D0036CA74DA3
APP文件里的UDID为:C9C5A77B-053F-35A7-B136-D0036CA74DA3
这一套文件是匹配的,我们就可以进行最终的符号化操作了。
使用如下命令进行符号化:
symbolicatecrash TestCrash.crash TestCrash.app.dSYM > log.crash
执行的过程中如果提示报错:
则执行:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
然后重新执行
symbolicatecrash TestCrash.crash TestCrash.app.dSYM > log.crash
几秒钟之后在查看我们的文件夹里会发现多了一个log.crash文件
这个就是我们符号化好的崩溃报告,打开如下:
OK,可以愉快的分析问题所在了~
三 终极操作-针对某一行地址使用命令行符号化
崩溃报告会反馈给我们当程序崩溃的时候操作系统正在执行的所有操作,如果针对某个线程的某个操作比较感兴趣,但是符号化列表又没有进行符号化,此时我们可以通过命令行针对性的去符号化某一行十六进制地址,看看他代表的是什么类型的什么任务。
使用命令行符号化某一行代码使用的文件比较少,仅仅需要dSYM文件就可以了。(如何获取dSYM文件请参照第二种方法的部分内容)
假如我们想看看崩溃报告里的这一行地址代表的信息:
需要使用如下命令:
atos -arch <BinaryArchitecture> -o <PathToDSYMFile>/Contents/Resources/DWARF/<BinaryName> -l <LoadAddress> <AddressesToSymbolicate>
几个参数取值如下:
BinaryArchitecture
查看最后一列标记的TestCrash的Architecture
就是它
PathToDSYMFile
dSYM文件地址
BinaryName
APP文件名
LoadAddress和AddressesToSymbolicate
所以使用示例如下:
cd到dSYM文件所在的文件夹,执行
atos -arch arm64 -o TestCrash.app.dSYM/Contents/Resources/DWARF/TestCrash -l 0x1044c4000 0x00000001044ca2c4
结果如下:
此时这一行十六进制编码对应的信息就符号化出来了。
补充:另一种获取dSYM文件的方法:
dSYM文件:
APP文件:
用这种方法找到的dSYM文件和APP文件一定要记得根据第二种方法里的操作验证一下UUID,否则符号化出来的报告是没有意义的。
网友评论