Symbolicating an iOS crash log without the dSYM file

文章翻译自 coderwall,内容有些改动。

每次都要上传 dSYM 文件到 bugly,总让我们以为只有 dSYM 才能将 crash log 符号化。然而,其实没有 dSYM 也是可以符号化。

首先,你需要 crash 对应的 ipa 文件,更准确的说是 ipa 解压后的二进制文件。
如果你不确定 crash log 对应的是哪个编译版本,你可以将 crash log 中的 UUID 和本地保存的 app 二进制文件进行对比。
通过这个方式找到 UUID:

dwarfdump -u /path/to/MyApp.app/MyApp

你可以先尝试用 symbolicatecrash 对 crash log 进行符号化,这时候你至少能看到系统调用的函数。
先试试不带 dSYM 参数的:

symbolicatecrash /path/to/MyApp_2012-10-01_Device.crash

如果是带 dSYM 参数的:

symbolicatecrash /path/to/MyApp_2012-10-01_Device.crash /path/to/MyApp.app.dSYM

如果可以成功执行,那么你运气很好。下面这几步你也不用看了。

为了找到 symbolicatecrash,先执行这句:

find /Applications/Xcode.app -name symbolicatecrash -type f

然后用上面的结果设置下别名:

export DEVELOPER_DIR='/Applications/Xcode.app/Contents/Developer'

alias symbolicatecrash='/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources/symbolicatecrash'

接下来,使用 atos 符号化每个内存地址。内存地址在 crash log 里,确保选对了对应的 cpu 架构版本,比如 armv7s。

atos -arch armv7 -o /path/to/MyApp.app/MyApp 0x0003b508

重复此操作,便能看到对应的所有堆栈。
这个很费时,需要搞一个脚本。
这里已经有人写了一个,地址在这,而且还非常清楚地解释了为何不用 dSYM 也可以符号化。

1  MyApp  0x0000000001e7acc6 0x000a9000 + 31268038

简单来说,通过函数被调用的动态地址 0x0000000001e7acc6 减去进程基地址 0x000a9000,这样就能获得函数的地址。而我们的 app 的二进制文件则保存着函数调用地址,依靠这个文件我们就能进行符号化。