iOS programmer

iOS 应用 crash 分析

2017-06-16  本文已影响199人  在_宥

前提

应用崩溃影响用户体验,所以减少iOS应用奔溃是提高应用质量的重要途径。

一、获取iOS应用 crash信息

1,通过itunes同步

路径是:  设置 -> 隐私 ->诊断与用量 ->诊断与用量数据。在这里可以看到设备上所有的设备崩溃日志.
在“诊断与用量”界面,建议用户选择自动发送,这样可以每天自动发送诊断和用量数据到itunes,来帮助开发者分析崩溃.
Mac OSX :~/Library/Logs/CrashReporter/MobileDevice/ 
可以看到所有和该电脑同步过的设备的崩溃日志(.crash文件)

2,使用Xcode

3,其他方式获取部分堆栈信息

二,获取应用的符号表

1,日志文件

获取日志信息后,需要对堆栈调用信息分析


crash调用堆栈信息如图,有4列:第1列是栈顺序;第2列是二进制包名;第3列是运行地址;第四列是函数的动态加载地址,即加号前面的地址。

2,dSYM文件

在Xcode每次Archives的是都会生成dSYM文件,所有每次打包的时候的都需要保留包文件。点击.xcarchive文件,显示包含内容,在该目录下有生成的dSYM文件。dSYM文件也是Mach-o格式,Mach-O格式全称为Mach Object文件格式的缩写,是mac上可执行文件的格式,类似于windows上的PE格式 (Portable Executable ), Linux上的elf格式 (Executable and Linking Format)。
Mach-O可以分为3个部分

该dSYM文件包含armv7和arm64两种架构的符号表。其中arm64的偏移地址时835520

3,UUID

每一个可执行程序都有一个build UUID来唯一标识。Crash日志包含发生crash的这个应用(app)的 build UUID以及crash发生的时候,应用加载的所有库文件的[build UUID]。UUID用来确定二进制包唯一标识

localhost:Test guogh$ grep "crashTest arm64" crashTest2017.crash 
0x1000cc000 - 0x1000d3fff crashTest arm64  <87f22ef6f56d3c7fac969d3416cd328a> /var/containers/Bundle/Application/13B84A6F-FB06-484B-8573-9390559A4A71/crashTest.app/crashTest

或者

localhost:Test guogh$ grep --after-context=2 "Binary Images:" crashTest2017.crash 
Binary Images:
0x1000cc000 - 0x1000d3fff crashTest arm64  <87f22ef6f56d3c7fac969d3416cd328a> /var/containers/Bundle/Application/13B84A6F-FB06-484B-8573-9390559A4A71/crashTest.app/crashTest
0x100124000 - 0x100153fff dyld arm64  <f54ed85a94253887886a8028e20ed8ba> /usr/lib/dyld

其中 0x1000cc000 就是模块的加载地址。

localhost:Test guogh$ xcrun dwarfdump --uuid dSYMs/crashTest.app.dSYM/Contents/Resources/DWARF/crashTest 
UUID: 6D16D164-DA42-31C8-8890-94895DB43C47 (armv7) dSYMs/crashTest.app.dSYM/Contents/Resources/DWARF/crashTest
UUID: 87F22EF6-F56D-3C7F-AC96-9D3416CD328A (arm64) dSYMs/crashTest.app.dSYM/Contents/Resources/DWARF/crashTest

或者appName.app/appName文件

localhost:Test guogh$ xcrun dwarfdump --uuid Products/Applications/crashTest.app/crashTest 
UUID: 6D16D164-DA42-31C8-8890-94895DB43C47 (armv7) Products/Applications/crashTest.app/crashTest
UUID: 87F22EF6-F56D-3C7F-AC96-9D3416CD328A (arm64) Products/Applications/crashTest.app/crashTest

需要三者的UUID的匹配才能正确的符号化。即都是:87F22EF6-F56D-3C7F-AC96-9D3416CD328A

三,符号化iOS Crash堆栈

我们拿到的crash信息是堆栈调用信息,所有信息都是16进制的内存地址,不能分析应用crash的原因,需要符号化才能分析。

1,使用Xcode

对于已经上架了appStore的应用的来说,crash文件通过用户上传到苹果服务器,Xcode可以直接下载下来,看到堆栈符号化的堆栈信息就和开发调试一样方便。

2, symbolicatecrash

symbolicatecrash是Xcode带的独立工具,可以拷贝出来使用。查找位置

localhost:~ guogh$ find /Applications/Xcode.app -name symbolicatecrash -type f
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

如果提示Error: "DEVELOPER_DIR" is not defined ,则执行
export DEVELOPER_DIR=/Applications/Xcode.app

把symbolicatecrash和奔溃日志,APP对应的.dSYM文件放在同一文件夹下,执行如下命令:

Symbolicatecrash + 崩溃日志.crash + APP对应的.dSYM文件 + > + 输出到的文件,
或者
Symbolicatecrash + 崩溃日志.crash + appName.app/appName + > + 输出到的文件,
如:
localhost:Test guogh$ ./symbolicatecrash crashTest2017.crash Products/Applications/crashTest.app/crashTest > aa.log

符号化前

Last Exception Backtrace:
0   CoreFoundation                  0x1843391b8 __exceptionPreprocess + 124
1   libobjc.A.dylib                 0x182d7055c objc_exception_throw + 56
2   CoreFoundation                  0x1842147f4 -[__NSArrayI objectAtIndex:] + 184
3   crashTest                       0x1000d0904 0x1000cc000 + 18692
4   crashTest                       0x1000d0864 0x1000cc000 + 18532
5   UIKit                           0x18a1ee924 -[UIViewController loadViewIfRequired] + 1056
6   UIKit                           0x18a1ee4ec -[UIViewController view] + 28
7   UIKit                           0x18a1f4c98 -[UIWindow addRootViewControllerViewIfPossible] + 76
8   UIKit                           0x18a1f2138 -[UIWindow _setHidden:forced:] + 272

symbolicatecrash 符号化后

Last Exception Backtrace:
0   CoreFoundation                  0x1843391b8 __exceptionPreprocess + 124
1   libobjc.A.dylib                 0x182d7055c objc_exception_throw + 56
2   CoreFoundation                  0x1842147f4 -[__NSArrayI objectAtIndex:] + 184
3   crashTest                       0x1000d0904 -[ViewController crashTest] (ViewController.m:29)
4   crashTest                       0x1000d0864 -[ViewController viewDidLoad] (ViewController.m:22)
5   UIKit                           0x18a1ee924 -[UIViewController loadViewIfRequired] + 1056
6   UIKit                           0x18a1ee4ec -[UIViewController view] + 28
7   UIKit                           0x18a1f4c98 -[UIWindow addRootViewControllerViewIfPossible] + 76
8   UIKit                           0x18a1f2138 -[UIWindow _setHidden:forced:] + 272

可以看到第3,4行已经符号化了,显示了哪个文件具体行数,对应代码


查看源码,找出代码crash的原因就容易的多了。但使用symbolicatecrash工具有很大的限制

3,使用命令行工具atos

命令格式:

 atos -o executable -arch architecture -l loadAddress address 

说明:

-[ViewController crashTest] (in crashTest) (ViewController.m:29)

四,总结

本文分析了如何获取用户的.crash文件,以及如何符号化的方法,对于分析应用crash很适用。

上一篇下一篇

猜你喜欢

热点阅读