如果你有过分析 iOS 崩溃日志的经验, 一定经常看到日志里出现很多 <redacted> 的字段这篇文章就是帮助开发者将这些字段符号化为对应的系统库方法名
如果你已经掌握了这方面的知识, 就直接去这里 iOS-System-Symbols, 下载我整理好的系统库符号文件吧
符号化的作用
当获取到 app 的 crash 日志时, 第一步就是将其符号化作用是把日志堆栈中的方法调用显示出来, 对于来自 app 内部的方法, 还能直接给出方法对应. m 文件的所在行
符号化前(这里项目的 Build Settings 里的 Strip Style 设为了 Debugging Symbols, 所以这里能直接看到 MyApp 的方法名更多和 symbol 相关的设置, 请看这里):
- Thread 7:
- 0 libsystem_kernel.dylib 0x000000018efb416c 0x18efb3000 + 4460 (mach_msg_trap + 8)
- 1 libsystem_kernel.dylib 0x000000018efb3fdc 0x18efb3000 + 4060 (mach_msg + 72)
- 2 MyApp 0x000000010091e558 0x1000bc000 + 8791384 (ksmachexc_i_handleExceptions + 148)
- 3 libsystem_pthread.dylib 0x000000018f097860 0x18f094000 + 14432 (<redacted> + 240)
- 4 libsystem_pthread.dylib 0x000000018f097770 0x18f094000 + 14192 (_pthread_start + 284)
符号化后:
- Thread 7:
- 0 libsystem_kernel.dylib 0x000000018efb416c mach_msg_trap + 8
- 1 libsystem_kernel.dylib 0x000000018efb3fdc mach_msg + 72
- 2 MyApp 0x000000010091e558 ksmachexc_i_handleExceptions (KSCrashSentry_MachException.c:233)
- 3 libsystem_pthread.dylib 0x000000018f097860 _pthread_body + 240
- 4 libsystem_pthread.dylib 0x000000018f097770 _pthread_body + 0
可以发现, frame 3 里
libsystem_pthread.dylib
的 < redacted > 变成了_pthread_body,frame 2 里 MyApp 的
ksmachexc_i_handleExceptions
变成了更为完整的
ksmachexc_i_handleExceptions (KSCrashSentry_MachException.c:233)
, 直接给出了方法及其所在文件和行数
详细的符号化方法, 请参考符号化 iOS Crash 文件的 3 种方法这里就不重复了
需要注意的是, 很多时候, crash 日志里并不会有 MyApp 的调用, 而全都是系统库的调用:
- Thread 0 name: Dispatch queue: com.apple.main-thread
- Thread 0 Crashed:
- 0 libobjc.A.dylib 0x000000018b816f30 0x18b7fc000 + 110384 (objc_msgSend + 16)
- 1 UIKit 0x0000000192e0a79c 0x192c05000 + 2119580 (<redacted> + 72)
- 2 UIKit 0x0000000192c4db48 0x192c05000 + 297800 (<redacted> + 312)
- 3 UIKit 0x0000000192c4d988 0x192c05000 + 297352 (<redacted> + 160)
- 4 QuartzCore 0x00000001900d6404 0x18ffc5000 + 1119236 (<redacted> + 260)
- 5 libdispatch.dylib 0x000000018bc551c0 0x18bc54000 + 4544 (<redacted> + 16)
- 6 libdispatch.dylib 0x000000018bc59d6c 0x18bc54000 + 23916 (_dispatch_main_queue_callback_4CF + 1000)
- 7 CoreFoundation 0x000000018cd79f2c 0x18cc9d000 + 905004 (<redacted> + 12)
- 8 CoreFoundation 0x000000018cd77b18 0x18cc9d000 + 895768 (<redacted> + 1660)
- 9 CoreFoundation 0x000000018cca6048 0x18cc9d000 + 36936 (CFRunLoopRunSpecific + 444)
- 10 GraphiCSServices 0x000000018e729198 0x18e71d000 + 49560 (GSEventRunModal + 180)
- 11 UIKit 0x0000000192c80628 0x192c05000 + 505384 (<redacted> + 684)
- 12 UIKit 0x0000000192c7b360 0x192c05000 + 484192 (UIApplicationMain + 208)
- 13 MyApp 0x0000000100016e54 0x100004000 + 77396 (_mh_execute_header + 77396)
- 14 libdyld.dylib 0x000000018bc885b8 0x18bc84000 + 17848 (<redacted> + 4)
这时候就必须符号化系统库了符号化后的日志:
- Thread 0 name: Dispatch queue: com.apple.main-thread
- Thread 0 Crashed:
- 0 libobjc.A.dylib 0x000000018b816f30 objc_msgSend + 16
- 1 UIKit 0x0000000192e0a79c -[UISearchDisplayController _sendDelegateDidBeginDidEndSearch] + 72
- 2 UIKit 0x0000000192c4db48 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 312
- 3 UIKit 0x0000000192c4d988 -[UIViewAnimationState animationDidStop:finished:] + 160
- 4 QuartzCore 0x00000001900d6404 CA::Layer::run_animation_callbacks(void*) + 260
- 5 libdispatch.dylib 0x000000018bc551c0 _dispatch_client_callout + 16
- 6 libdispatch.dylib 0x000000018bc59d6c _dispatch_main_queue_callback_4CF + 1000
- 7 CoreFoundation 0x000000018cd79f2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
- 8 CoreFoundation 0x000000018cd77b18 __CFRunLoopRun + 1660
- 9 CoreFoundation 0x000000018cca6048 CFRunLoopRunSpecific + 444
- 10 GraphicsServices 0x000000018e729198 GSEventRunModal + 180
- 11 UIKit 0x0000000192c80628 -[UIApplication _run] + 684
- 12 UIKit 0x0000000192c7b360 UIApplicationMain + 208
- 13 MyApp 0x0000000100016e54 main (main.m:15)
- 14 libdyld.dylib 0x000000018bc885b8 start + 4
可以看出是 UISearchController 的 delegate 导致的问题, 检查一下就发现
UISearchDisplayController
的 delegate 是 assign 的, 是由于点击搜索条的同时 pop 了界面导致的 crash
从这里可以发现, 符号化系统库是很有必要的
如何符号化系统库
符号化自己 app 的方法名, 需要编译 ipa 时生成的 dySYM 文件而要将系统库的 < redacted > 符号化为完整的方法名, 也需要系统库的符号文件
1. 匹配对应的符号文件版本
系统库符号文件不是通用的, 而是对应 crash 所在设备的系统版本和 CPU 型号的
crash 日志中有这样两个信息:
- Code Type: ARM-64
- OS Version: iOS 10.2 (14C82)
Code Type 表示此设备的 CPU 为 armv7armv7s 还是 arm64
OS Version 表示此设备的系统版本号, 括号中的字符串代表了此系统的 build 号可以在这里查找 build 号: iOS SDK,iOS version history
2. 将对应版本的符号文件放到指定目录
这时候, 把获取到的对应版本的符号文件放到 Mac 的
~/Library/Developer/Xcode/iOS DeviceSupport
目录下, 再使用符号化 iOS Crash 文件的 3 种方法里提到的 Xcode 自带的符号化工具 symbolicatecrash 进行符号化这个工具会自动搜索系统库符号文件
获取系统符号文件的 4 个方法
从真机上获取
大部分系统库符号文件只能从真机上获取, 苹果也没有提供下载 当你用 Xcode 第一次连接某台设备进行真机调试时, 会看到 Xcode 显示
Processing symbol files
, 这时候就是在拷贝真机上的符号文件到 Mac 系统的
/Users/xxx/Library/Developer/Xcode/iOS DeviceSupport
目录下
目录下的 10.2(14C82)这样的文件夹就是对应的符号文件, 通常都有 1-3GB 的大小, 很占用空间, 动不动就累积成 340GB 很多讲清理 Mac 垃圾文件的教程都会说要删除这个目录下的文件, 真是坑爹正确做法是做成压缩包保存到外部硬盘里, 需要符号化的时候再重新解压到此目录
寻找苹果官方的下载地址
之前 watch 的调试出现 bug 时, 有人找出过几个 watch 的符号文件下载地址见 No symbols for paired Apple Watch 但是我尝试按照对应的命名格式, 并没有找到 iOS 符号文件的下载地址
从已解密的固件中提取符号文件
某些已经被破解的固件可以直接提取系统文件, 但是未破解的固件(较新的固件和 arm64 的固件), 无法用这种方式获取
固件解密步骤:
1. 下载对应版本的. ipsw 固件, 直接解压, 解压后里面有几个. dmg 格式的镜像文件, 最大的. dmg 文件就是系统镜像
2. 从 Firmware_Keys 找到对应固件的解密 key(页面上 Root Filesystem 字段的 key)
3. 用一个 dmg 工具进行解密, 下载地址使用方式: cd 到解压后的 ipsw 文件夹, 执行
./dmg extract xxx-xxxx-xxx.dmg dec.dmg -k <key>
extract 后面跟两个参数, 分别是系统镜像 dmg 的名字和解密后的文件名,-k 后面填写第 2 步获取到的 key, 如果 key 不对, 解密会失败
4. 等待最终会生成一个 dec.dmg 文件, 双击打开即可加载系统镜像
提取符号文件方法: 参考聊聊从 iOS 固件提取系统库符号中的
二系统库符号提取
部分
下载旧版本 Xcode, 提取 SDK
旧版本的 Xcode 里包含了对应的 iPhoneSDK, 可以从中获得符号文件 路径是
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/
里面的 System/Library 里就可以看到 framework, 而且同时包含了 armv7,armv7s,arm643 个平台的版本
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/version.plist
可以查看是哪个版本把 iPhoneOS.sdk 文件夹的名字改成对应的
CFBundleVersion (ProductBuildVersion)
格式, 然后在里面加一层 Symbols 子文件夹, 把 System,Library,usr 都放进 Symbols 里, 就可以和其他符号文件一样使用了
但是当 iOS 版本只包含了 bug 修复, 而没有改变 API,Xcode 就不会有附带对应的 SDK, 还是需要从真机上获取而且从 Xcode7 开始, 苹果用 tbd 文件代替了真机符号文件, 所以这个方法也失效了 参考: Xcode software image for user iOS in order to symbolicate iOS calls, Missing iOS symbols at ~/Library/Developer/Xcode/iOS DeviceSupport
获取符号文件的难题
这个时候, 游戏就开始了:
很多时候 crash 日志只给出了系统的调用栈, 不能直接定位到自己 app 的代码, 因此需要符号化系统库
用户的 crash 来自各种系统版本, 需要对应版本的系统符号文件才能符号化
系统库符号文件只能从真机上获取, 苹果没有提供下载
从 iOS 7.0(11A465)到 iOS 10.2(14C92)一共有 50 个 build 版本, 公司的测试机是不会覆盖到这么变态的完整度的
同一个版本, 有时候会给 iPhone 和 iPad 甚至 6 和 6s 提供不同 build 的固件
某些版本是某些机子的特供版, 例如 10.0.3(14A551)是 iPhone 7 和 7 Plus 独有的, 这就更加大了收集难度
同一个 iOS 版本可能有多个 build, 例如 10.1(14B72)和 10.1(14B72c), 苹果觉得更新幅度太小, 就没有提升版本号
除了 build 号的区别, 符号文件在不同 CPU 平台上也有区别, 意味着来自 4s(armv7)和 6s(arm64)的符号文件, 即便 build 号是一样的, 也无法通用所以 50 个 build 号又要翻倍, 达到了 88 个, 所以精确来说我只是收集了 (63/88) 的进度幸运的是, arm64 机型的系统库里附带了 armv7s
规则好厉害的收集游戏啊收集品其实还有稀有度的区别, 其中最厉害的应该是
10.0
, 这是 iPhone 7 和 7 Plus 独有的出厂系统, 而且没有固件可以下载, 因此即便有 iPhone 7 也不能通过刷机来得到
10.0
其实我一直很奇怪为什么很少见到开发者抱怨找不到系统符号文件, 从而召集大家进行收集并分享, 猜测可能的原因是:
懒遇到无法符号化的问题, 没有去解决
有些公司可能很早就开始对 crash 日志自动符号化了, 因此很早就开始收集符号文件只要一直跟着苹果的每一个版本升级, 收集起来还是挺简单的而这些资源, 开发者并不会注意到可以共享出来
crash 收集和符号化使用的是第三方服务, 第三方平台会帮助符号化系统库
但是我找了一下, 没有找到一家明确声明了能够符号化所有系统库的第三方平台从腾讯的 Bugly 论坛里也能发现, 有些系统方法并没有符号化出来, 系统库是缺失的(update: 找到了一个国外的平台, 在 stack overflow 上说能符号化所有版本的系统库, 但是是收费服务, 我也没有测试)
在公司小组里, 大部分时候都是我来分析 crash 日志, 所以当遇到缺少系统符号文件的情况, 就会十分无奈很多时候, 没有符号化的 crash 日志根本无法提供有用信息
系统符号文件下载地址
暴力收集
收集不全一直让我很不爽之前搜刮了组内的测试机, 只收集到了有限的几个 (感谢无私提供 iPhone 7 让我刷机降级的同事) 终于, 这周末特意跑去了一趟二手机市场寻找旧版本的设备来拷贝, 总算是收集得完整了一点, 但是也花了我 121 块钱
心情总算愉悦了
其中大部分都是拷贝自 arm64 设备的, armv7 的符号文件收集我是放弃了有哪位大侠有兴趣把这个游戏玩通关的吗? 还有 tvOS 和 watchOS 的符号, 我也放弃了 (update: 又花了些时间从 Xcode 的 SDK 和固件里提取了 armv7s 和 armv7 的固件, 现在只剩下几个 arm64 的版本了)
整理了一下传到了网盘, 地址见下方, 有需要的去下载吧
目前还缺少的符号文件
如果有人有这几个符号文件的, 恳请你分享!
分享可以直接贴下载地址, 也可以提交到这个 github 项目 iOS-System-Symbols 如果我得到了新的符号文件, 也会在这个项目里更新
缺失符号的版本 | 缺失的 CPU 版本 | 描述 |
---|---|---|
11.2 (15C113) | arm64 | iPhone X 独占 |
11.1 (15B101) | arm64 | iPad Pro2 12.9 寸 和 iPad Pro 10.5 寸 独占 |
10.0(14A346) | arm64 | iPhone 7 和 7 Plus 独占,出厂自带系统 |
9.3.2(13F72) | arm64 | iPad Pro 9.7 寸独占,修复了变砖的问题 |
9.3(13E237) | arm64 | 5s, iPad Air 和 iPad mini2 独占,修复了不能激活的问题 |
9.3(13E234) | arm64 | 6s, 6s Plus 和 iPad Pro 9.7 寸 独占 |
8.1.1 (12B435) | arm64 | 5s, iPad Air 和 iPad mini2 独占 |
8.0.1(12A402) | arm64 | 8.0.1 有导致变砖的 bug,发布后很快就停止推送了 |
7.1.2 (11D257) | arm64 | |
7.0.2(11A501) | arm64 | |
7.0.1(11A470a) | arm64 | 5s 独占 |
注意, arm64,armv7s,armv7 版本的文件都是在同一个文件里的(例如
/Symbols/System/Library/Frameworks/UIKit.framework/UIKit
),Xcode 在拷贝 armv7 的符号文件时, 如果 iOS DeviceSupport 目录里已经有 arm64 或 armv7s 的符号文件, 则会自动进行合并因此如果你要分享一个 armv7 版本的符号文件, 请先把 arm64 等其他版本的拷贝到
/Users/zhangweike/Library/Developer/Xcode/iOS DeviceSupport/
里, 然后再用 Xcode 进行合并后再压缩分享
下载地址
下载地址请见这个项目: iOS-System-Symbols 如果我得到了新的符号文件, 会在这个项目里更新
我把里面的那几个
dyld_shared_cache_xxxx
大文件单独拿出来了, 目的是减小压缩包大小如果只是符号化的话, 用不到这几个文件, 只是在真机调试的时候才需要
符号文件版本列表
这些是我已经收集到的符号文件, 包括了对应的 CPU 信息 iOS10 系统开始不支持 armv7 的机器但是 iOS9 以下还是支持 armv7 的
查看是否带有对应 CPU 架构的符号文件的方式: 到
10.2 (14C92)/Symbols/System/Library/Caches/com.apple.dyld
这样的目录下, 会有对应的
- dyld_shared_cache_arm64
- ,
- dyld_shared_cache_armv7s
- ,
- dyld_shared_cache_armv7
文件, 如果缺失了, 就说明对应的 CPU 架构符号文件还不存在
版本 | 已收集到的 CPU 版本 | 描述 |
---|---|---|
11.2.6 (15D100) | arm64 | |
11.2.5 (15D60) | arm64 | |
11.2.2 (15C202) | arm64 | |
11.2.1 (15C153) | arm64 | |
11.2 (15C114) | arm64 | |
11.2 (15C113) | none | iPhone X 独占 |
11.1.2 (15B202) | arm64 | |
11.1.1 (15B150) | arm64 | |
11.1 (15B101) | none | iPad Pro2 12.9 寸 和 iPad Pro 10.5 寸独占 |
11.1 (15B93) | arm64 | |
11.0.3 (15A432) | arm64 | |
11.0.2 (15A421) | arm64 | |
11.0.1 (15A403) | arm64 | iPhone 8 和 8 Plus 独占 |
11.0.1 (15A402) | arm64 | |
11.0 (15A372) | arm64 | |
10.3.3 (14G60) | arm64,armv7s | |
10.3.2 (14F91) | arm64,armv7s | iPad mini4(Cellular) 独占 |
10.3.2 (14F90) | arm64,armv7s | iPad (5th gen) 独占 |
10.3.2 (14F89) | arm64,armv7s | |
10.3.1 (14E304) | arm64,armv7s | |
10.3 (14E277) | arm64,armv7s | |
10.2.1 (14D27) | arm64,armv7s | |
10.2 (14C92) | arm64,armv7s | |
10.1.1 (14B150) | arm64,armv7s | |
10.1.1 (14B100) | arm64,armv7s | |
10.1 (14B72c) | arm64,armv7s | |
10.1 (14B72) | arm64,armv7s | |
10.0.3 (14A551) | arm64,armv7s | |
10.0.2 (14A456) | arm64,armv7s | |
10.0.1 (14A403) | arm64,armv7s | |
10.0(14A346) | none | iPhone 7 和 7 Plus 独占,出厂自带系统 |
9.3.5 (13G36) | arm64,armv7s,armv7 | |
9.3.4 (13G35) | arm64,armv7s,armv7 | |
9.3.3 (13G34) | arm64,armv7s,armv7 | |
9.3.2(13F72) | none | iPad Pro 9.7 寸独占,修复了变砖的问题 |
9.3.2 (13F69) | arm64,armv7s,armv7 | |
9.3.1 (13E238) | arm64,armv7s,armv7 | |
9.3(13E237) | armv7s,armv7 | 5s 和更旧机型独占,修复了不能激活的问题 |
9.3(13E236) | armv7 | iPad2 独占,修复了不能激活的问题 |
9.3(13E234) | none | 6s, 6s Plus and iPad Pro 9.7 寸独占 |
9.3 (13E233) | arm64,armv7s,armv7 | |
9.2.1 (13D20) | arm64,armv7s | iPhone 6 和更新的机型独占 |
9.2.1 (13D15) | arm64,armv7s,armv7 | |
9.2 (13C75) | arm64,armv7s,armv7 | |
9.1 (13B143) | arm64,armv7s,armv7 | |
9.0.2(13A452) | arm64,armv7s,armv7 | |
9.0.1(13A404) | arm64,armv7s,armv7 | |
9.0 (13A344) | arm64,armv7s,armv7 | |
8.4.1 (12H321) | arm64,armv7s,armv7 | |
8.4 (12H143) | arm64,armv7s,armv7 | |
8.3 (12F70) | arm64,armv7s,armv7 | iPhone 独占 |
8.3 (12F69) | arm64,armv7s,armv7 | iPad 独占 |
8.2 (12D508) | arm64,armv7s,armv7 | |
8.1.3 (12B466) | arm64,armv7s,armv7 | |
8.1.2 (12B440) | arm64,armv7s,armv7 | |
8.1.1 (12B436) | arm64,armv7s | iPhone 6 和更新的机型独占 |
8.1.1 (12B435) | armv7s,armv7 | 5s 和更旧机型独占 |
8.1 (12B411) | arm64,armv7s,armv7 | iPhone 独占 |
8.1 (12B410) | arm64,armv7s,armv7 | iPad 独占 |
8.0.2 (12A405) | arm64,armv7s,armv7 | |
8.0.1(12A402) | armv7s,armv7 | 8.0.1 有导致变砖的 bug,发布后很快就停止推送了 |
8.0 (12A366) | arm64,armv7s | 6 Plus 独占 |
8.0 (12A365) | arm64,armv7s,armv7 | |
7.1.2 (11D257) | armv7s,armv7 | |
7.1.1 (11D201) | arm64,armv7s,armv7 | |
7.1 (11D167) | arm64,armv7s,armv7 | |
7.0.6 (11B651) | arm64,armv7s,armv7 | |
7.0.4 (11B554a) | arm64,armv7s,armv7 | |
7.0.3 (11B511) | arm64,armv7s,armv7 | |
7.0.2(11A501) | armv7s,armv7 | |
7.0.1(11A470a) | armv7s | 5s 和 5c 独占 |
7.0(11A465) | arm64,armv7s,armv7 |
机型对应 CPU 架构
CPU | 机型 |
---|---|
armv6 | iPhone, iPhone2, iPhone3G, iPod Touch 1 and 2 |
armv7 | iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini,iPod Touch 3G, iPod Touch4, iPod Touch5 |
armv7s | iPhone5, iPhone5C, iPad4(iPad with Retina Display) |
arm64 | iPhone5S, iPad Air, iPad mini2(iPad mini with Retina Display), iPhone6, iPhone6s, iPhone7, iPhone7s and any new device in the future |
结束语
最后再次呼吁一下, 如果谁有上面缺失的符号文件, 就请共享一下吧虽然只是做一点微小的工作, 但是能够有很大帮助
不觉得填满上面那个列表会很爽吗?
额外提示
其实这些符号文件就是真机上的系统库, 包括了完整的系统库二进制文件有时候要反编译某些系统 framework, 但是模拟器 SDK 里没有对应的 framework(比如只有真机上才有的
CoreMotion.framework
), 就可以在这些真机上的系统库里找到了
参考
www.jianshu.com/p/11710e7ab
符号化 iOS Crash 文件的 3 种方法
- iOS SDK
- iOS version history
- No symbols for paired Apple Watch
聊聊从 iOS 固件提取系统库符号
- Xcode software image for user iOS in order to symbolicate iOS calls
- Missing iOS symbols at ~/Library/Developer/Xcode/iOS DeviceSupport
来源: https://juejin.im/post/5ab7dece6fb9a028ba1f7218