iOS 崩溃排查技巧:如何获取系统库源码
编者荐语:
做个小调查,有多少朋友了解为什么系统库会有版本号信息?
以下文章来源于老司机技术周报 ,作者酷酷的哀殿
作者:酷酷的哀殿
APP 崩溃会导致用户体验下降,严重时甚至会导致用户卸载 APP。我希望从实际问题中去分享一些我日常工作上的小技巧,希望可以帮助到大家。
今天要分享的是「如何获取系统库源码」,问题源自于一位朋友遇到了一个系统库相关的 crash,一直无法定位到具体原因,所以想了解一下「如何根据 iOS 崩溃日志获取对应系统库源码」,正好我之前也遇到过类似的问题,所以和大家分享一下我的一些办法。
基础术语对齐
按照惯例,为了方便提高效率,避免歧义,第一部分是基础术语对齐。
如下,我们从官方文档 Examining the Fields in a Crash Report 的截取部分标准的崩溃日志进行讲解。
Incident Identifier: 6156848E-344E-4D9E-84E0-87AFD0D0AE7B
CrashReporter Key: 76f2fb60060d6a7f814973377cbdc866fffd521f
Hardware Model: iPhone8,1
Process: TouchCanvas [1052]
Path: /private/var/containers/Bundle/Application/51346174-37EF-4F60-B72D-8DE5F01035F5/TouchCanvas.app/TouchCanvas
Identifier: com.example.apple-samplecode.TouchCanvas
Version: 1 (3.0)
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: com.example.apple-samplecode.TouchCanvas [1806]
Date/Time: 2020-03-27 18:06:51.4969 -0700
Launch Time: 2020-03-27 18:06:31.7593 -0700
OS Version: iPhone OS 13.3.1 (17D50)
22 libdyld.dylib 0x00000001b6728360 start + 4
OS Version
:系统版本号,13.3.1
OS Build Version
:系统编译版本号,17D50
二进制文件
:二进制文件名,libdyld.dylib
为了方便方便区分 13.3.1 与 17D50,本文的概念与官方概念存在略微差异,敬请理解。
另外,我们下面还会用以下术语:
PROJECT_NAME
:项目名,比如dyld
。PRODUCT_NAME
,构建产物名称,通常与PROJECT_NAME
一致比如 libdyld.dylib
就是由lib
+dyld
+.dylib
组合而成,dyld
就是PRODUCT_NAME
CURRENT_PROJECT_VERSION
:项目版本号
根据OS Version
定位源码
操作步骤:
结合
Xcode
发布文档,我们推测iPhone OS 13.3.1
对应的macOS
版本可能是10.15.2
在 https://opensource.apple.com/ 找到对应的版本链接:
iOS 13.3.1 macOS 10.15.2
根据二进制文件名
:libdyld.dylib
猜测对应的PROJECT_NAME
是dyld
对照 macOS 10.15.2 ,可以猜测CURRENT_PROJECT_VERSION
是 733.8
点击dyld-733.8
右侧的 ⬇️ 按钮进行下载
如果没有找到对应的源码文件,则尝试查找上一个系统版本,比如
[macOS 10.15.1] (https://opensource.apple.com/release/macos-10151.html)、 [macOS 10.15] (https://opensource.apple.com/release/macos-1015.html)
经过实际测试,大部分情况都可以根据二进制文件
都能够找到对应的源码。
但是仍然会遇到以下两类问题:
1.CURRENT_PROJECT_VERSION
不够精确。
对于 iPhone OS 13.3.1
,我们无法准确得知对应的macOS
系统版本号
2.部分情况无法根据二进制文件
反推出对应的 PROJECT_NAME
比如,我们无法根据libsystem_asl.dylib
找到与 system_asl
相关的源码
优化一
根据
OS Build Version
获取PROJECT_VERSION
操作步骤:
1、在 ~/Library/Developer/Xcode/iOS\ DeviceSupport
目录下查找到对应的二进制文件
。
cd ~/Library/Developer/Xcode/iOS\ DeviceSupport
find . -name libdyld.dylib
输出:
./14.0 (18A373) arm64e/Symbols/usr/lib/system/libdyld.dylib
2、根据第1步的结果,我们发现本机只有14.0 (18A373) arm64e
版本,与我们需要查找的 13.3.1 (17D50)
不符。所以,尝试通过搜索引擎查找。
比如 iOS-System-Symbols 就维护了超过100个系统符号文件目录的压缩版本。
3、通过 llvm-objdump
命令打印该二进制文件
相关的二进制库信息
llvm-objdump -m --dylibs-used ./Symbols/usr/lib/system/libdyld.dylib
输出:
./Symbols/usr/lib/system/libdyld.dylib:
/usr/lib/system/libdyld.dylib (compatibility version 1.0.0, current version 828.4.0)
/usr/lib/system/libsystem_platform.dylib (compatibility version 1.0.0, current version 254.0.0, upward)
/usr/lib/system/libsystem_malloc.dylib (compatibility version 1.0.0, current version 317.0.1, upward)
/usr/lib/system/libsystem_c.dylib (compatibility version 1.0.0, current version 1439.0.3, upward)
/usr/lib/system/libsystem_pthread.dylib (compatibility version 1.0.0, current version 454.0.0, upward)
/usr/lib/system/libxpc.dylib (compatibility version 1.0.0, current version 2038.0.15, upward)
/usr/lib/system/libsystem_blocks.dylib (compatibility version 1.0.0, current version 78.0.0, upward)
/usr/lib/system/libsystem_kernel.dylib (compatibility version 1.0.0, current version 7195.0.43, upward)
/usr/lib/system/libsystem_sandbox.dylib (compatibility version 1.0.0, current version 1441.0.4, upward)
/usr/lib/system/libdispatch.dylib (compatibility version 1.0.0, current version 1271.0.4, upward)
/usr/lib/system/libcorecrypto.dylib (compatibility version 1.0.0, current version 1000.0.5, upward)
/usr/lib/system/libcompiler_rt.dylib (compatibility version 1.0.0, current version 102.3.0, upward)
从输出的第2行,可以发现 libdyld.dylib
对应的CURRENT_PROJECT_VERSION
是 828.4.0
优化二
根据
OS Build Version
获取PROJECT_NAME
操作步骤:
1、以 libsystem_asl.dylib
为例,先通过find
命令定位二进制文件的位置
find . -name libsystem_asl.dylib
输出:
./Symbols/usr/lib/system/libsystem_asl.dylib
2、通过 llvm-objdump -s
对整个二进制文件进行 dump 操作,并通过 grep
命令筛选 section __const
的内容
考虑到下载系统符号文件会占用较大的空间,作者没有下载
17D50
对应的符号文件,而是以18A373
为例进行说明
llvm-objdump -s ./Symbols/usr/lib/system/libsystem_asl.dylib | grep "Contents of section __const" -A 3
输出:
Contents of section __const:
19a1c19f0 40282329 50524f47 52414d3a 61736c20 @(#)PROGRAM:asl
19a1c1a00 2050524f 4a454354 3a737973 6c6f672d PROJECT:syslog-
19a1c1a10 3338350a 00000000 00000000 00107840 385...........x@
--
Contents of section __const:
1d1641d18 00000000 00000000 20000000 00000000 ........ .......
1d1641d28 821b1c9a 01001000 00000000 00000000 ................
1d1641d38 ba1c1c9a 01000800 6c1c1c9a 01000800 ........l.......
--
Contents of section __const:
1db1b7de8 00000000 00000000 00d91a1a 00005880 ..............X.
1db1b7df8 00000000 00000000 00000000 00000000 ................
1db1b7e08 00000000 00000000 00000000 00000000 ................
我们很容易发现以下内容:
@(#)PROGRAM:asl PROJECT:syslog-385
实际上,根据 Xcode
提供的Build System
资料,我们可以得到以下信息:
PRODUCT_NAME
:asl
PROJECT_NAME
:syslog
PROJECT_VERSION
:385
3、根据上一步的结果结果,直接打开 https://opensource.apple.com/tarballs/syslog
目录并选择对应的版本。
在作者写本文时
14.0 (18A373) arm64e
对应的syslog-385
还未开源。所以,我们只能下载到 syslog-377.40.1.tar.gz
总结
本文分享了两种特殊的技巧定位崩溃日志对应的源码。
如果有读者发现了其它方案,欢迎加入我们的微信群,一起参与讨论。
优点 | 缺点 | |
---|---|---|
系统版本号 | 简单,无需对应的符号文件 | * 无法无法准确定位对应源码工程名问题 * 存在无法准确定位源码版本问题 |
系统编译版本号 | * 无法无法准确定位对应源码工程名问题 * 存在无法准确定位源码版本问题 | 需要下载对应的符号文件(通常在1G以上) |
关注我们
我们是「老司机技术周报」,每周会发布一份关于 iOS 的周报,也会定期分享一些和 iOS 相关的技术。欢迎关注。