您的位置:首页 > 其它

如何手动解析CrashLog

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

一、.dSYM

.dSYM(debuggingSYMbols)又称为调试符号表,是苹果为了方便调试和定位问题而使用的一种调试方案,本质上使用的是起源于贝尔实验室的DWARF(DebuggingWithAttributedRecordFormats),其在.xcarchive目录中的层次结构为:

1
2
3
4
5
6
.xcarchive
--dSYMs
|--Your.app.dSYM
|--Contents
|--Resources
|--DWARF
关于DWARF的具体内容以后有机会再说。我们能解析CrashLog全靠.dSYM文件,解析方式见后文。

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

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

1、从崩溃日志中获取UUID

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

1
2
BinaryImages:
0xa2000-0x541fffYourarmv7/var/mobile/Containers/Bundle/Application/645D3184-4C20-4161-924B-BDE170FA64CC/Your.app/Your
从中可以看到关于你应用的若干信息:

代码段的起终地址为:0xa2000–0x541fff

运行你应用的CPU指令集为:armv7

应用的UUID为:a5c8d3cfda65396689e4370bf3a0ac64(不区分大小写)

2、从符号表中获取UUID

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

1
dwarfdump--uuidYour.app.dSYM
或者:

1
dwarfdump--uuidYour.app.dSYM/Contents/Resources/DWARF/Your
执行结果为:

1
UUID:A5C8D3CF-DA65-3966-89E4-370BF3A0AC64(armv7)Your.app.dSYM/Contents/Resources/DWARF/Your
由此得到armv7指令集的UUID为:A5C8D3CF-DA65-3966-89E4-370BF3A0AC64(如果你的二进制文件支持多个指令集,这里会列出每个指令集对应符号表的UUID),通过和崩溃日志中的对比发现二者一致,才可进行进一步的解析操作。

三、计算崩溃符号表地址

以下面的崩溃堆栈为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Thread0:
0libobjc.A.dylib0x33f10f600x33efe000+77664
1Foundation0x273526ac0x2734a000+34476
2Foundation0x27355c3e0x2734a000+48190
3UIKit0x29ef9d1c0x29bbc000+3398940
4UIKit0x29ef9c9a0x29bbc000+3398810
5UIKit0x29ef954c0x29bbc000+3396940
6UIKit0x29c3a16a0x29bbc000+516458
7UIKit0x29e4b8e60x29bbc000+2685158
8UIKit0x29c3a1280x29bbc000+516392
9Your0x000f08460xa2000+321606
10UIKit0x29e90fb20x29bbc000+2969522
11UIKit0x29e910760x29bbc000+2969718
12UIKit0x29e867cc0x29bbc000+2926540
13UIKit0x29c9e8ea0x29bbc000+927978
14UIKit0x29bc8a6a0x29bbc000+51818
15QuartzCore0x295f0a080x295e4000+51720
16QuartzCore0x295ec3e00x295e4000+33760
17QuartzCore0x295ec2680x295e4000+33384
18QuartzCore0x295ebc4c0x295e4000+31820
19QuartzCore0x295eba500x295e4000+31312
20QuartzCore0x295e59280x295e4000+6440
21CoreFoundation0x266d0d920x26604000+839058
22CoreFoundation0x266ce44e0x26604000+828494
23CoreFoundation0x266ce8560x26604000+829526
24CoreFoundation0x2661c3bc0x26604000+99260
25CoreFoundation0x2661c1ce0x26604000+98766
26GraphicsServices0x2da1a0a40x2da11000+37028
27UIKit0x29c2a7ac0x29bbc000+452524
28Your0x0024643a0xa2000+1721402
29libdyld.dylib0x34484aac0x34483000+6828
1、符号表堆栈地址计算方式

要想利用符号表解析出崩溃对应位置,需要计算出符号表中对应的崩溃堆栈地址。而从上述堆栈中第9行可以看到,应用崩溃发生在运行时地址0x000f0846,该进程的运行时起始地址是0xa2000,崩溃处距离进程起始地址的偏移量为十进制的321606(对应十六进制为0x4E846)。三者对应关系:

1
0x000f0846=0xa2000+0x4E846
对应的公式为:

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

1
符号表堆栈地址=符号表起始地址+偏移量
2、获取符号表中的TEXT段起始地址

符号表中TEXT段的起始地址可以通过以下命令获得:

1
$otool-lYour.app.dSYM/Contents/Resources/DWARF/Your
运行结果中的片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
Loadcommand3
cmdLC_SEGMENT
cmdsize736
segname__TEXT
vmaddr0x00004000
vmsize0x00700000
fileoff0
filesize0
maxprot0x00000005
initprot0x00000005
nsects10
flags0x0
其中的vmaddr0x00004000字段即为TEXT段的起始地址。

3、计算符号表地址

由公式:

1
符号表堆栈地址=符号表起始地址+偏移量
可得:

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

四、崩溃信息还原

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

1、dwarfdump

命令如下:

1
$dwarfdump--archarmv7Your.app.dSYM--lookup0x52846|grep'Linetable'
需要注意的是:

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

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

—lookup后面跟的一定是经过准确计算的符号表中的崩溃地址

使用dwarfdump解析的结果较杂乱,因此使用grep命令抓取其中关键点展示出来

运行结果如下:

1
2
Linetabledir:'/data/.../Src/OBDConnectSetting/Controller'
Linetablefile:'OBDFirstConnectViewController.m'line882,column5withstartaddress0x000000000052768
其中第一行是编译时文件目录,第二行包含了崩溃发生的文件名称以及文件中具体行号等信息,有了这些信息就能准确定位崩溃原因啦。

2、atos

atos是另一种更加简洁的崩溃日志解析方法,使用方式如下:

1
$atos-oLuBao-archarmv70x52846
其执行结果如下:

1
-[OBDFirstConnectViewControllershowOilPricePickerView](inYour)(OBDFirstConnectViewController.m:882)
相对dwarfdump命令的解析结果,更加简洁直观的指出了崩溃发生的位置。

3、无需符号表崩溃地址的解析方式

实际上,atos还提供了另外一种无需计算崩溃地址对应的符号表地址的方式,命令格式如下:

1
$atos-oYour.app.dSYM/Contents/Resources/DWARF/Your-archarmv7-l0xa20000x000f0846
其中-l选项指定了二进制文件在运行时的起始地址0xa2000(获取方式见BinaryImages相关内容),后面跟的是崩溃发生的运行时地址0x000f0846,解析结果和使用计算得到的符号表中崩溃地址一致:

1
-[OBDFirstConnectViewControllershowOilPricePickerView](inYour)(OBDFirstConnectViewController.m:882)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: