手动解析CrashLog 方法

解决崩溃问题是移动应用开发者最日常的工作之一。如果是开发过程中遇到的崩溃,可以根据重现步骤调试,但线上版本就无能为力了。好在目前已经有很多不错的第三方CrashLog搜集平台(如友盟、Crashlytics等)为我们做好了解析工作,甚至在Xcode9里苹果也跟进了解析线上版本崩溃日志的功能,为开发者减轻了不少负担。尽管通常已经不需要我们手工处理CrashLog,了解CrashLog的还原原理和方法还是有必要的。


一、确定符号表和崩溃日志的一致性



有了符号表文件,有了崩溃日志文件,在解析之前一定要确保二者的对应关系,否则就算按照下述步骤解析出内容也肯定是不准确的。二者的对应关系可以通过UUID来确定。


1、从崩溃日志中获取UUID


崩溃日志比较靠下的位置有个BinaryImages模块,其第一行内容如下:


Binary Images: 0xa2000 - 0x541fff Your armv7  <a5c8d3cfda65396689e4370bf3a0ac64>/var/mobile/Containers/Bundle/Application/645D3184-4C20-4161-924B-BDE170FA64CC/Your.app/Your

从中可以看到关于你应用的若干信息:

  • 代码段的起终地址为:0xa2000 – 0x541fff
  • 运行你应用的CPU指令集为:armv7
  • 应用的UUID为:a5c8d3cfda65396689e4370bf3a0ac64(不区分大小写)


2、从符号表中获取UUID


执行以下命令从符号表中提取UUID:


dwarfdump --uuid ettNextGen.dSYM

执行结果为:


UUID: EE215358-70DB-3ECF-BF53-A3A09E146619 (arm64)ettNextGen.dSYM/Contents/Resources/DWARF/ettNextGen

二、section信息提取


保存在DAWARF中的信息是高度压缩的,可以通过dwarfdump命令从中提取出可读信息。前文所述的那些section中,定位CrashLog只需要用到.debug_info和.debug_line。由于解析出来的数据量较大,为了方便查看,就将其保存在文本中。两个section的数据提取方式如下


.debug_info


dwarfdump -e --debug-info /Users/kangxg/Desktop/未命名文件夹/ettNextGen.dSYM/Contents/Resources/DWARF/ettNextGen >info-e.txt

.debug_line


dwarfdump -e --debug-info /Users/kangxg/Desktop/未命名文件夹/ettNextGen.dSYM/Contents/Resources/DWARF/ettNextGen >line-e.txt

命令中的-e可以增加解析结果的可读性;其它section的提取方式类似,详情请参考dwarfdump命令帮助信息。


三、计算崩溃符号表地址


1 获取符号表中的TEXT段起始地址


otool -l /Users/kangxg/Desktop/未命名文件夹/ettNextGen.dSYM/Contents/Resources/DWARF/ettNextGen

 运行结果中的片段如下:


Load command 3
      cmd LC_SEGMENT_64
  cmdsize 1832
  segname __TEXT
   vmaddr 0x0000000100000000
   vmsize 0x0000000000e9c000
  fileoff 0
 filesize 0
  maxprot 0x00000005
 initprot 0x00000005
   nsects 22
    flags 0x0

其中的 vmaddr0x0000000100000000 字段即为TEXT段的起始地址。


2 崩溃堆栈信息


Thread 0:
0   libobjc.A.dylib                   0x33f10f60 0x33efe000 + 77664
1   Foundation                        0x273526ac 0x2734a000 + 34476
2   Foundation                        0x27355c3e 0x2734a000 + 48190
3   UIKit                             0x29ef9d1c 0x29bbc000 + 3398940
4   UIKit                             0x29ef9c9a 0x29bbc000 + 3398810
5   UIKit                             0x29ef954c 0x29bbc000 + 3396940
6   UIKit                             0x29c3a16a 0x29bbc000 + 516458
7   UIKit                             0x29e4b8e6 0x29bbc000 + 2685158
8   UIKit                             0x29c3a128 0x29bbc000 + 516392
9   Your                              0x000f0846 0xa2000 + 321606
10  UIKit                             0x29e90fb2 0x29bbc000 + 2969522
11  UIKit                             0x29e91076 0x29bbc000 + 2969718
12  UIKit                             0x29e867cc 0x29bbc000 + 2926540
13  UIKit                             0x29c9e8ea 0x29bbc000 + 927978
14  UIKit                             0x29bc8a6a 0x29bbc000 + 51818
15  QuartzCore                        0x295f0a08 0x295e4000 + 51720
16  QuartzCore                        0x295ec3e0 0x295e4000 + 33760
17  QuartzCore                        0x295ec268 0x295e4000 + 33384
18  QuartzCore                        0x295ebc4c 0x295e4000 + 31820
19  QuartzCore                        0x295eba50 0x295e4000 + 31312
20  QuartzCore                        0x295e5928 0x295e4000 + 6440
21  CoreFoundation                    0x266d0d92 0x26604000 + 839058
22  CoreFoundation                    0x266ce44e 0x26604000 + 828494
23  CoreFoundation                    0x266ce856 0x26604000 + 829526
24  CoreFoundation                    0x2661c3bc 0x26604000 + 99260
25  CoreFoundation                    0x2661c1ce 0x26604000 + 98766
26  GraphicsServices                  0x2da1a0a4 0x2da11000 + 37028
27  UIKit                             0x29c2a7ac 0x29bbc000 + 452524
28  Your                              0x0024643a 0xa2000 + 1721402
29  libdyld.dylib                     0x34484aac 0x34483000 + 6828

符号表堆栈地址计算方式


0x000f0846 = 0xa2000 + 0x4E846

  对应的公式为:


运行时堆栈地址 = 运行时起始地址 + 偏移量

   崩溃堆栈中的起始地址和崩溃地址均为运行时地址,根据虚拟内存偏移量不变原理,只要提供了符号表TEXT段的起始地址,再加上偏移量(这里为0x4E846)就能得到符号表中的堆栈地址,即:


符号表堆栈地址 = 符号表起始地址 + 偏移量

3、计算符号表地址


由上面的公式可得:


0x52846 = 0x4E846 + 0x4000

即符号表中的崩溃地址为0x52846,接下来就可以根据这个地址解析出崩溃位置了。


四、崩溃信息还原


有了符号表的崩溃地址,有以下几种方式解析崩溃信息:


1、dwarfdump


命令如下:


$dwarfdump --arch armv7 Your.app.dSYM --lookup 0x52846 |grep 'Line table'

需要注意的是:

  • 这里的armv7是运行设备的CPU指令集,而不是二进制文件的指令集

比如armv7指令集的二进制文件运行在arm64指令集的设备上,这个地方应该写arm64。

  • —lookup后面跟的一定是经过准确计算的符号表中的崩溃地址
  • 使用dwarfdump解析的结果较杂乱,因此使用grep命令抓取其中关键点展示出来


运行结果如下:


Line table dir :'/data/.../Src/OBDConnectSetting/Controller' Line table file:'OBDFirstConnectViewController.m' line 882, column 5 with start address0x000000000052768

其中第一行是编译时文件目录,第二行包含了崩溃发生的文件名称以及文件中具体行号等信息,有了这些信息就能准确定位崩溃原因啦。


http://www.foggry.com/blog/2017/07/27/ru-he-shou-dong-jie-xi-crashlog/


http://www.foggry.com/blog/2017/08/10/ru-he-shou-dong-jie-xi-crashlogzhi-yuan-li-pian/


w3/2017-2015/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值