iOS开发 -- 分析CrashLog (1) symbolicatecrash+Organizer

Crash是开发者心中永远的痛,iOS开发中也经常遇到Crash,幸好善解人意的Apple帮我们记录下了Crash现场--CrashLog;

App Crash后,系统会帮我们把崩溃日志存下来,方便我们进行崩溃分析。


1.导出crashlog

xcode自带的Organizer能够帮助我们轻松取出log,可以按快捷键Command+shift+2打开,例如下图demo crash后产生log。


上图右边便是我们crash时的现场。可以点屏幕下方的Export进行导出给别人(或者叫别人导出给你,例如测试人员)


网上的文章一般教大家用xcode自带的symbolicatecrash工具把log解出来,其实这种方式是有点不太对头的,我曾经被坑过。各种泪~~

不过先一步一步讲吧,先按照常规用symbolicatecrash进行解log

等等~忘记说为什么要解log了··

仔细观察crashlog,可以看到如下:

0   CoreFoundation                	0x31321e7e __exceptionPreprocess + 126
1   libobjc.A.dylib               	0x3b67e6c2 objc_exception_throw + 34
2   CoreFoundation                	0x313257b2 -[NSObject(NSObject) doesNotRecognizeSelector:] + 198
3   CoreFoundation                	0x313240aa ___forwarding___ + 702
4   CoreFoundation                	0x31272dc4 _CF_forwarding_prep_0 + 20
5   CrashDemo                     	0x0009b290 0x94000 + 29328
6   UIKit                         	0x33aaa956 -[UIViewController loadViewIfRequired] + 514
7   UIKit                         	0x33aaa714 -[UIViewController view] + 20
8   UIKit                         	0x33ab13ec -[UIWindow addRootViewControllerViewIfPossible] + 60
9   UIKit                         	0x33aaeae0 -[UIWindow _setHidden:forced:] + 304
10  UIKit                         	0x33b19828 -[UIWindow makeKeyAndVisible] + 56
11  UIKit                         	0x33b165f8 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1652
12  UIKit                         	0x33b10b3c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 716
13  BaiduInputMethod.dylib        	0x001e868e 0xeb000 + 1037966
14  UIKit                         	0x33aaba02 -[UIApplication handleEvent:withNewEvent:] + 3138
15  UIKit                         	0x33aaacf8 -[UIApplication sendEvent:] + 68
16  UIKit                         	0x33b1031c _UIApplicationHandleEvent + 660
17  GraphicsServices              	0x35f90768 _PurpleEventCallback + 604
18  GraphicsServices              	0x35f90352 PurpleEventCallback + 30
19  CoreFoundation                	0x312ec772 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30
20  CoreFoundation                	0x312ec70e __CFRunLoopDoSource1 + 342
21  CoreFoundation                	0x312eaeda __CFRunLoopRun + 1402
22  CoreFoundation                	0x3125546c CFRunLoopRunSpecific + 520
23  CoreFoundation                	0x3125524e CFRunLoopRunInMode + 102
24  UIKit                         	0x33b0f5be -[UIApplication _run] + 758
25  UIKit                         	0x33b0a840 UIApplicationMain + 1132
26  CrashDemo                     	0x0009b36a 0x94000 + 29546
27  libdyld.dylib                 	0x3bb77ab2 tlv_initializer + 2

其中第5行很可能就是我们要找的关键crash点(因为很明显其他的都是系统库ಥ_ಥ),不过悲剧的是这一行没显示出具体符号表,只显示出了符号表地址 ಥ_ಥ~~~,所以这就是我们要解crashlog的原因。好,开始·

首先:

解crashlog要用到xcode自带的一个工具symbolicatecrash,他在/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash

需要先在环境变量里加入

DEVELOPER_DIR=/Applications/XCode.app/Contents/Developer
export DEVELOPER_DIR

并且可以把symbolicatecrash 软连到usr/sbin下,方便以后用


2.然后:

解crashlog需要crash的那个app的符号表文件(.dSYM),所以大家发包时记得把这个文件存一下,用于后面分析



开始:

打开命令行,把xx.crash和xx.app.dSYM反正同一目录下(别放在/tmp目录下,后面我会告诉你为啥),然后运行 

symbolicatecrash CrashDemo.crash CrashDemo.app.dSYM >crashlog.txt

然后打开crashlog.txt 会得到结果如下

Last Exception Backtrace:
0   CoreFoundation                	0x31321e7e __exceptionPreprocess + 126
1   libobjc.A.dylib               	0x3b67e6c2 objc_exception_throw + 34
2   CoreFoundation                	0x313257b2 -[NSObject(NSObject) doesNotRecognizeSelector:] + 198
3   CoreFoundation                	0x313240aa ___forwarding___ + 702
4   CoreFoundation                	0x31272dc4 _CF_forwarding_prep_0 + 20
5   CrashDemo                     	0x0009b290 -[ViewController viewDidLoad] (ViewController.m:21)
6   UIKit                         	0x33aaa956 -[UIViewController loadViewIfRequired] + 514
7   UIKit                         	0x33aaa714 -[UIViewController view] + 20
8   UIKit                         	0x33ab13ec -[UIWindow addRootViewControllerViewIfPossible] + 60
9   UIKit                         	0x33aaeae0 -[UIWindow _setHidden:forced:] + 304
10  UIKit                         	0x33b19828 -[UIWindow makeKeyAndVisible] + 56
11  UIKit                         	0x33b165f8 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1652
12  UIKit                         	0x33b10b3c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 716
13  BaiduInputMethod.dylib        	0x001e868e 0xeb000 + 1037966
14  UIKit                         	0x33aaba02 -[UIApplication handleEvent:withNewEvent:] + 3138
15  UIKit                         	0x33aaacf8 -[UIApplication sendEvent:] + 68
16  UIKit                         	0x33b1031c _UIApplicationHandleEvent + 660
17  GraphicsServices              	0x35f90768 _PurpleEventCallback + 604
18  GraphicsServices              	0x35f90352 PurpleEventCallback + 30
19  CoreFoundation                	0x312ec772 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30
20  CoreFoundation                	0x312ec70e __CFRunLoopDoSource1 + 342
21  CoreFoundation                	0x312eaeda __CFRunLoopRun + 1402
22  CoreFoundation                	0x3125546c CFRunLoopRunSpecific + 520
23  CoreFoundation                	0x3125524e CFRunLoopRunInMode + 102
24  UIKit                         	0x33b0f5be -[UIApplication _run] + 758
25  UIKit                         	0x33b0a840 UIApplicationMain + 1132
26  CrashDemo                     	0x0009b36a main (main.m:16)
27  libdyld.dylib                 	0x3bb77ab2 tlv_initializer + 2

我们可以看到,之前只显示地址的一行(第5行)变成可读的代码了,而且后面还跟上了行号,这下crash就能容易定位多了吧~


等等,还没完,上面是理想状态,如果你人品不好(例如我),那有可能得不到以上结果,那就要找找原因了,一般原因有以下几种:

1.dSYM文件和crash文件不对应(就算一样的代码,打两次包,dSYM都可能不一样,不一样就解不出来,所以务必记住)

2.放的位置不对,例如刚说不要反在/tmp目录下


首先针对第一种可能,我们可以验证一下dysm文件的UUID和clashLog文件的是否对应,只有这两个文件的UUID完全一致了,才能保证解出来的log是正确的

查看dysm文件的UUID可以用例如:dwarfdump -u xx.dSYM  

tmpLog|⇒ dwarfdump -u CrashDemo.app.dSYM
UUID: 6F6C3E53-2D27-3D51-8A5B-65E94476372F (armv7) CrashDemo.app.dSYM/Contents/Resources/DWARF/CrashDemo
UUID: 36DBB225-755E-366E-B8B6-8B2F38C767E8 (armv7s) CrashDemo.app.dSYM/Contents/Resources/DWARF/CrashDemo
UUID: 4A302375-CA31-35E8-8B45-05A789CDB707 (arm64) CrashDemo.app.dSYM/Contents/Resources/DWARF/CrashDemo

crash log的UUID可以直接用记事本打开查看,位置在Binary Images的下一行:


dSYM解出来的UUID可能有多个,这个根据你编译选项而定,只要有一个对上就行


如果这种和情况没问题,那应该就是第二种情况导致的了,关于第二种情况导致的原因,和如何避让,我们得看下symbolicatecrash的源代码是咋实现的。


看了上面截图,你是不是明白了点什么?对,符号表文件的查找是通过mdfind 来查找的,也就是spotlight!那么刚才的命令其实直接用symbolicatecrash xxx.crash >xx.log 也是可以的!

这下你知道为啥不能反正/tmp目录下了吧,因为spotlight不收录/tmp目录,如果你放在/tmp目录下就导致symbolicatecrash找不到符号表文件(其他不被spotlight收录的目录也有这问题)。


好,上面两个问题解决了,相信解个log不再是啥问题了。那接下来我们来想想问啥symbolicatecrash会有上面提到的第二个问题,我想了好久得出的结论是:

symbolicatecrash不是给我们用的,而是给Organizer用的!所以我们正确解log的办法应该是把.dSYM文件和crash文件放一起(非/tmp),然后打开Organizer,点Import!然后点Re-Symbolicate (如果不行多点几次,spotlight收录需要点时间)

然后看看,log是不是解出来了?是不是人性化了很多很多?O(∩_∩)O~~


PS:基于以上理论,你应该能明白为啥如果是自己打的包,crashLog会自动被解出来了吧?O(∩_∩)O~~欢迎留言讨论


3.没有dSYM文件咋办?

请看下篇文章 iOS开发 -- 分析CrashLog (2) 无dsym文件解crashlog



总结:

1.不建议直接使用symbolicatecrash,应该用Organizer

2.symbolicatecrash依赖spotlight工作,所以不要把符号表文件反正spotlight没收录的地方

3.打包是养成备份dSYM文件的习惯


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值