iOS Crash 收集与符号化

2017/05/24 blog

硌,当我们提交到AppStore 上的app 崩溃了,我想此时我们的内心也是崩溃的。此时,我们应该做的就是赶紧从iTunes store上下载crash log。可是crash log下载下来了。

下载下来后,打开一看

Last Exception Backtrace:
0   CoreFoundation 0x000000018708b100 0x186f80000 + 1093888
1   libobjc.A.dylib            0x00000001939441fc 0x19393c000 + 33276
2   CoreFoundation 0x000000018708b040 0x186f80000 + 1093696
3   ApteligentExampleApp 0x000000010003acc4 0x10002c000 + 60612

你能看得懂吗,反正我是看不懂。

这时我们得想办法变成能看懂的东西,那就是符号化crash log了。要想符号化,我们得找到对应的文件,编译器在编译的时候为每个二进制文件和对应的.dsym 文件提供了一个唯一识别码–UUID

注意:每一个二进制都一个UUID,crash log 也包含一个UUID,即使是相同的代码,相同的编译设置,重新编译也会产生不同的UUID。

废话不多说,先来看看crash文件

$ grep --after-context=2 "Binary Images:" ~/Desktop/crashlog/DemoSandbox.crash      
Binary Images:
0x100048000 - 0x100053fff DemoSandbox arm64  <a913f9e410ab3389a4bb7a03c4343d60> /var/mobile/Containers/Bundle/Application/DCCE1746-C533-4F40-85D3-41EFC4B87EF4/DemoSandbox.app/DemoSandbox
0x10007c000 - 0x10007ffff MobileSubstrate.dylib arm64  <3134cfb2f722310ea2c742ae4dc131ab> /Library/MobileSubstrate/MobileSubstrate.dylib
0x1002ec000 - 0x1002effff SubstrateLoader.dylib arm64      

此时的 a913f9e410ab3389a4bb7a03c4343d60 就是这份crash log 对应的二级制的UUID了。再来看看二进制的UUID。

$ xcrun dwarfdump --uuid /Users/heyonly/Library/Developer/Xcode/DerivedData/emm-gcfmioqsbcxmerceaefbrzjkatft/Build/Products/Debug-iphoneos/DemoSandbox.app/DemoSandbox 
UUID: A913F9E4-10AB-3389-A4BB-7A03C4343D60 (arm64) /Users/heyonly/Library/Developer/Xcode/DerivedData/emm-gcfmioqsbcxmerceaefbrzjkatft/Build/Products/Debug-iphoneos/DemoSandbox.app/DemoSandbox

这个app有2个UUID,表明它是一个fat binaray

同样检查你的.dsym 文件中:

$ xcrun dwarfdump --uuid /Users/heyonly/Library/Developer/Xcode/DerivedData/emm-gcfmioqsbcxmerceaefbrzjkatft/Build/Products/Debug-iphoneos/DemoSandbox.app.dSYM/Contents/Resources/DWARF/DemoSandbox 
UUID: A913F9E4-10AB-3389-A4BB-7A03C4343D60 (arm64) /Users/heyonly/Library/Developer/Xcode/DerivedData/emm-gcfmioqsbcxmerceaefbrzjkatft/Build/Products/Debug-iphoneos/DemoSandbox.app.dSYM/Contents/Resources/DWARF/DemoSandbox

嗯,三个文件对应起来了。

symbolicatecrash

symbolicatecrash 是一个将堆栈地址符号化的脚本,输入参数是苹果官方格式的崩溃日志及本地的.dsym文件。基本使用方式如下:

./symbolicatecrash Example.crash Example.app.dSYM > Control_symbol.crash

但使用symbolicatecrash 工具有很大的限制

(1)只能分析官方格式的崩溃日志,需要从具体的设备中导出,获取和操作不是很方便

(2)符号化的结果也是没有具体的行号信息的,也经常出现符号化失败的情况。

实际上,Xcode的organizers 内置了symbolicatecrash工具,所以我们在实际开发中基本上只要打开crash log ,xcode就已经帮我们符号化了。

atos

当然,我们也有另外一个符号化工具,这个就比较强大,但是不是很方便,倒是可以自己写一个脚本,笔者在后边提供了一个只有二进制文件没有符号文件的情况下使用atos 来符号化的脚本,这是后话,我们先来看看atos 的使用方式:

atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>

我们知道APP启动都有一个模块加载地址和偏移地址,他们的关系是怎么样的呢。下面用一张图来说明:

Last Exception Backtrace:
0   CoreFoundation 0x000000018708b100 0x186f80000 + 1093888
1   libobjc.A.dylib            0x00000001939441fc 0x19393c000 + 33276
2   CoreFoundation 0x000000018708b040 0x186f80000 + 1093696
3   ApteligentExampleApp 0x000000010003acc4 0x10002c000 + 60612
Binary Images:
0x10002c000 - 0x1000dffff ApteligentExampleApp arm64  <3759a98e880336108b1a799afa3c1adc> /var/mobile/Applications/46FB38F8-0E69-459F-B96A-CEEA21B77D55/ApteligentExampleApp.app/ApteligentExampleApp

有了这些概念后,我们就来分析crash log 了。

符号化你的crash log

当你获取到了crash log,相对应的二进制文件,符号化文件,三者都对应后,使用以下命令,直接一键符号化。

atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>

如上图:

atos -arch arm64 -o ApteligentExampleApp.dSYM -l 0x10002c000 0x000000010003acc4
-[ApteligentExampleClass buggyFunction] (in ApteligentExampleApp.dSYM) (ApteligentExampleClass.m:181)

这没什么问题。

有时候,我们想偷个懒,没有必要恢复怎么符号表,只要稍微给点信息,我们就解决,我只想看看crash 在哪个函数中。

比如有这么一段崩溃信息:

16  CoreFoundation                	0x183fddcd8 __CFRunLoopRun + 724
17  CoreFoundation                	0x183f0cca0 CFRunLoopRunSpecific + 384
18  UIKit                         	0x18962a1c8 -[UIApplication _run] + 460
19  UIKit                         	0x189624ffc UIApplicationMain + 204
20  DemoSandbox                   	0x1000e82a0 0x1000e0000 + 33440
21  libdyld.dylib                 	0x19933a8b8 start + 4
Binary Images:
0x1000e0000 - 0x1000ebfff DemoSandbox arm64  <a913f9e410ab3389a4bb7a03c4343d60> /var/mobile/Containers/Bundle/Application/7839DCA5-8955-4796-8142-6932ACDB873A/DemoSandbox.app/DemoSandbox

这样我们看的更清楚,0x1000e0000就是我们模块的加载地址

接下来我们在没有符号文件的情况下来看看

$ atos -arch arm64 -o /Users/heyonly/Library/Developer/Xcode/DerivedData/emm-gcfmioqsbcxmerceaefbrzjkatft/Build/Products/Debug-iphoneos/DemoSandbox.app/DemoSandbox -l 0x1000e0000 0x1000e82a0
main (in DemoSandbox) (main.m:14)

这样是不是很清晰明了

有人就会说,我们开发的我们都会有符号文件。嗯,有一种情况会用的到,在做非越狱手机进行开发的时候很管用 为此,我专门写了个脚本,进行自动化分析,还可以,挺管用的

项目地址:https://github.com/heyonly/hbsymbolicate

很方便:

sh symbol.sh -l <path/ipa.crash> -b <path/example.app/example> -o destination.crash

不是很好用,我有时间会来优化优化

总结

有点乱,慢慢就会好了,欢迎拍砖,貌似拍砖要搭梯子哦😯

参见:

[1]:https://www.apteligent.com/technical-resource/symbolicating-an-ios-crash-report/ [2]:https://developer.apple.com/library/content/technotes/tn2151/_index.html [3]:https://developer.apple.com/library/content/technotes/tn2151/_index.html [4]:https://read01.com/nj6BRm.html

Search

    Post Directory