崩溃问题是日常开发中亟需解决的问题之一,线上的问题更是如此,应用中经常嵌入第三方统计平台,如友盟也提供了不错的日志收集能力,以下就介绍下对于友盟统计收集到的应用崩溃信息,如何基于符号表.dSYM文件进行分析;
关于符号表:
“符号表文件实际是从Mach-O文件中抽取的调试信息而得到的文件目录”,可以理解为保存了调试数据堆栈信息的一个集合;
我们使用Xcode编译归档(Archive)的时候会自动为我们生成.dSYM文件;
关于符号表数据的存储格式这里不做讨论,但需要知道的是保存在其中的信息都是高度压缩的,如果需要提取需要使用相应的命令,我们一会会介绍到;
现在我们知道了符号表的存在,以及可以通过命令提取出符号表中的调试信息;接下来回到CrashLog上来;
一份CrashLog:
对于线上的Crash,友盟提供了不错的收集功能,我们可以在错误列表检查Crash的详细日志;
日志中标红的部分指出了运行时发生崩溃的堆栈地址,利用符号表分析Crash的方式就是要计算出基于符号表的崩溃的堆栈地址,分析其调试信息,解决bug;
Crash的分析:
1.找到线上版本对应的.dSYM文件:
这个只需要到已经归档的App列表中找到对应的线上版本的归档记录;show in finder;
2.获取UUID 并与崩溃日志的UUID比对 得出对应的CPU指令集类型:(这里是arm64)
dwarfdump --uuid XXXXXXXXXX.app.dSYM
根据UUID也可以找到对应的符号表文件:
mdfind "com_apple_xcode_dsym_uuids == EC8390FC-32B1-3062-BCDD-92EFXXXXXXXXX"
/Users/XXXXXXXXX/Library/Developer/Xcode/Archives/2019-03-06/XXXXXXXXX 2019-3-6 上午11.40.xcarchive
/Users/XXXXXXXXX/Library/Developer/Xcode/Archives/2019-03-06/XXXXXXXXX 2019-3-6 上午10.36.xcarchive
/Users/XXXXXXXXX/Library/Developer/Xcode/Archives/2019-03-05/XXXXXXXXX 2019-3-5 下午2.34.xcarchive
3.根据崩溃的堆栈信息 计算发生Crash位置基于运行时Base Address的偏移量:
0x00000001011da428
-
0x0000000100f30000
==2aa428
4.获取符号表的base address 计算崩溃位置在符号表中的堆栈地址:
otool -l XXXXXXXX.app.dSYM/Contents/Resources/DWARF/XXXXXXXX //默认的armv7
otool -arch arm64 -l XXXXXXXX.app.dSYM/Contents/Resources/DWARF/XXXXXXXX //arm64
0x0000000100000000
+
0x00000000002aa428
=
0x00000001002aa428
5.最后根据计算出的地址获取调试信息:
筛选内容的三个层次:(筛选出的结果会指明堆栈地址对应的调试信息)
dwarfdump --arch arm64 XXXXXXX.app.dSYM
dwarfdump --arch arm64 XXXXXXX.app.dSYM --lookup 0x1002aa428
dwarfdump --arch arm64 XXXXXXX.app.dSYM --lookup 0x1002aa428 | grep 'Line table'
友盟的符号表分析:
一种简洁的方式是使用友盟提供的分析符号表的功能:
首先将符号表.dSYM文件压缩到桌面testxxx文件夹:
//(-r表示递归压缩)
//示例1:把我的笔记中的所有内容 压缩到桌面的testxxx文件夹 压缩文件名为testxxx.zip
zip -r /Users/XXXXXXX/Desktop/testxxx/testxxx.zip ./我的笔记/* -x "\.*”
//示例2:把当前目录中的所有内容缩到当前目录 压缩文件名为testxxx.zip
zip -r testxxx.zip ./testxxx/* -x "\.*”
//在符号表目录下执行如下命令 将符号表文件压缩到桌面指定文件夹(事先需要建一个)
zip -r /Users/XXXXXXX/Desktop/testxxx/testxxx.zip ./* -x "\.*"
解压缩后上传至友盟符号表管理,待分析完毕后,再次查看错误列表中的记录,如果Crash地址可分析,相应的调试信息会展示出来;
Application received signal SIGABRT
最后对于我们上边的出现的那个问题,有必要做下说明:
如果你去搜索Application received signal SIGABRT这个问题的话,你会在友盟的文档回复中找到这个类型,但是它并没有什么用,他告诉你的只是这是个bug,且足以引发崩溃,但是没办法获取到CrashLog;简单来说这种崩溃不是代码层面的,而是应用层面的,也就是说引起崩溃的不是由于你写了哪段有问题的代码,而是由于应用级的问题,应用被系统干掉了;
(应用中有时还会由于数据同步问题造成了Crash,可以通过代码捕获相应的Crash,上传至自己的服务器,然后给出提示性文字,结束进程,登出用户状态,让用户重新登陆App,这种补救处理方式也未尝不可)
这里所说的无法捕获CrashLog的崩溃,只能自己分析了,而且这种崩溃多半在真机上调试时都是必现的,可能是获取系统权限没声明造成或是其他原因,如果你没有复现,建议你找一个与出问题的机型一样的机器跑下,就可以查到了。