iOS Crash 符号化解析
在公司的时候,通常 Crash 平台都做的很好,帮我们做好了符号化解析,一些三方平台也会提供类似的能力。
但我们还是会遇到需要自己做符号化解析的场景,比如某些线下包没有解析成功,又比如离开了公司提供的环境的时候等等。
所以我们还是有必要了解如何做符号化解析。
准备工作
先准备好原始崩溃栈和符号表文件 xxx.dSYM
。
另:有关对应关系,可以通过崩溃日志的Binary Images
看到架构和UUID
,检查UUID
和dSYM
是否一致。
我们通常看到的崩溃栈的每行如下:
1 | 11 XXXAPP 0x00000001001e7ff4 0x100078000 + 1507316 |
先明确下后3列的含义,分别是 运行时地址
、运行时基地址
、崩溃处距离进程起始地址的偏移量
3者的关系是 运行时地址
= 运行时基地址
+ 偏移量
留意前2个是16进制,偏移量是10进制,做运算时要注意,如上文中的:
0x00000001001e7ff4
= 0x100078000
+ 1507316(0x16FFF4)
虚拟内存偏移量,拿到符号表TEXT段的起始地址,再加上偏移量,就能得到符号表中的堆栈地址:
符号表堆栈地址
= 符号表基地址
+ 偏移量
符号表TEXT段起始地址获取方式:
1 | otool -l xxx.dSYM/Contents/Resources/DWARF/xxx |
留意,这里也区分了架构,留意崩溃所发生的架构:armv7
对应 LC_SEGMENT
,arm64
对应 LC_SEGMENT_64
。而 vmaddr
部分就是我们要的符号表基地址。
所以我们有时候在网上看到教程里提到让我们用 0x0000000100000000
做计算,原因就在这里。
单行解析
常见的有两种方案:
dwarfdump
1 | export dSYMPath="$(find ~/Library/Developer/Xcode -iname '*.dSYM' -print0 | xargs -0 dwarfdump -u | grep 62304F1D-278A-489D-B66E-77199CDDDD4B | sed -E 's/^[^/]+//' | head -n 1)"; |
这段代码其实是很多三方平台里会自动提示给你的,简单来说就是使用 dwarfdump
命令。其中 grep
的就是 UUID
,第1行目的是得到 dSYMP
的路径。
--arch
对应架构,--lookup
后面的就是我们要计算的对应符号表的位置,即:符号表堆栈地址
= 符号表基地址
+ 偏移量
假如是 arm64
,则这个计算就是:0x0000000100000000
+ 1507316
= 0x10016FFF4
atos
还有一种方案是使用 atos
命令,而这个命令提供了2种方式。
第1种和 dwarfdump
类似,需要预先计算出符号表偏移量,计算方式同上。
1 | xcrun atos -o xxx.dSYM/Contents/Resources/DWARF/xxx -arch armv7 0x98040 |
第2种则不用我们自己自己计算。
1 | $ xcrun atos -o xxx.dSYM/Contents/Resources/DWARF/xxx -l 0x100078000 0x00000001001e7ff4 -arch arm64 |
其中 -l
指定的是代码 运行时基地址
,即崩溃栈的 +
前面的地址,后面跟着的是崩溃发生的 运行时地址
,即崩溃栈显示的第1个地址。
整体解析
symbolicatecrash
事实上,单行解析效率不高,很多时候,可能更多的是整个 crash 文件解析,我们可以使用 Xcode
提供的 symbolicatecrash
工具。
1 | export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer |
symbolicatecrash
命令的2个入参,分别是 crash
文件和 dSYM
。
留意:
symbolicatecrash
需要完整的路径,/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
第1行
export DEVELOPER_DIR
,一般情况下是需要的,否则会出现如下报错:1
Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line xx
说明
本文仅仅介绍了工具使用相关的技巧,有关符号化更深层次的含义、一些系统库一般不容易符号化的场景如何处理、Swift
和C++
的场景又会遇到哪些问题,本文没有详细描述。