iOS 应用 crash 分析

前提

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

一、获取iOS应用 crash信息

1,通过itunes同步

  • 1,iOS设备上的应用闪退时, 操作系统会声称一个崩溃日志, 保存在设备上。
路径是:  设置 -> 隐私 ->诊断与用量 ->诊断与用量数据。在这里可以看到设备上所有的设备崩溃日志.
在“诊断与用量”界面,建议用户选择自动发送,这样可以每天自动发送诊断和用量数据到itunes,来帮助开发者分析崩溃.
  • 2,设备与电脑上的ITunes Store同步后, 会将崩溃日志保存在电脑上,崩溃日志保存在以下位置:
Mac OSX :~/Library/Logs/CrashReporter/MobileDevice/ 
可以看到所有和该电脑同步过的设备的崩溃日志(.crash文件)

2,使用Xcode

  • 1,code的Window菜单下的organizer,然后点击Devices tab,然后选中左边的Device Logs。选中某一个崩溃日志,点击Export Log可导出崩溃日志(.crash文件)


  • 2,通过Xcode 获取appStore上架应用的crash信息。


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

  • 1,通过代码获取应用的crash堆栈信息,然后下次启动时上传服务器获得日志信息。
  • 2,通过友盟等第三方SDK拿到应用crash部分堆栈信息。
    这种方式获取的应用信息都只有部分堆栈信息

二,获取应用的符号表

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个部分

  • (1)Header
  • (2)Segment
  • (3)section
    header后面是segment,然后再跟着section,而一个segment是可以包含多个section的。MachOview工具可以可视化查看Mach-O文件格式,我们把dSYM文件放入可视化工具:


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

3,UUID

每一个可执行程序都有一个build UUID来唯一标识。Crash日志包含发生crash的这个应用(app)的 build UUID以及crash发生的时候,应用加载的所有库文件的[build UUID]。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 就是模块的加载地址。

  • 查看二进制文件的UUID,dSYM文件
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工具有很大的限制

  • 只能分析官方格式的崩溃日志,需要从具体的设备中导出,获取和操作都不是很方便
  • 符号化的结果也是没有具体的行号信息的,也经常会出现符号化失败的情况。
  • 实际上, Xcode的Organizer内置了symbolicatecrash工具,所以开发者才可以直接看到符号化的崩溃堆栈日志。

3,使用命令行工具atos

命令格式:

 atos -o executable -arch architecture -l loadAddress address 

说明:

  • executable dYSM文件或二进制执行文件appName.app/appName
  • loadAddress 表示函数的动态加载地址,对应崩溃地址堆栈中 + 号前面的地址,即0x1000cc000
  • address 表示运行时地址、对应崩溃地址堆栈中第一个地址,即0x1000d0904 ,实际上,崩溃地址堆栈中+号前后的地址相加即是运行时地址,即0x1000cc000 + 18692= 0x1000d0904
  • 执行命令查询地址的符号,可以看到如下结果:
-[ViewController crashTest] (in crashTest) (ViewController.m:29)

四,总结

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 37,496评论 45 122
  • 前言 崩溃是让发人员比较头痛的事情,app崩溃了,说明代码写的有问题,这时如何快速定位到崩溃的地方很重要。调试阶段...
    進无尽阅读 1,963评论 0 9
  • LLVM简介 XCode4.0以后,LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化...
    苦工阅读 9,521评论 1 16
  • 本文就捕获iOS Crash、Crash日志组成、Crash日志符号化、异常信息解读、常见的Crash五部分介绍。...
    xukuangbo_阅读 1,565评论 0 0
  • 前言 iOS崩溃是让iOS开发人员比较头痛的事情,app崩溃了,说明代码写的有问题,这时如何快速定位到崩溃的地方很...
    齐滇大圣阅读 65,222评论 29 443