iOS 用 dSYM 文件解析崩溃日志
iOS 项目打包成功后为 xcarchive
后缀的文件, 里面不但包含了 app 运行所需要的二进制文件和资源文件,还含有项目中编程时具体文件的信息。App 运行时,内存中仅仅加载了二进制文件,出现异常时,只能反映出 16 进制的内存地址,还需要通过 dSYM 文件映射为对应的具体文件信息,编程人员才能定位问题,进行更正。具体是个什么过程呢?
打开 xcarchive
文件,可以找到 app
后缀的文件,其中包含了 ipa
包的全部信息。
查看包内容,能够看到里面有 app 运行所需要的图片,nib 文件和 bundle 资源文件,除此之外,最重要的是 Unix 可执行文件。
file MTAppProduction
MTAppProduction: Mach-O universal binary with 2 architectures: [arm_v7:Mach-O executable arm_v7] [arm64]
MTAppProduction (for architecture armv7): Mach-O executable arm_v7
MTAppProduction (for architecture arm64): Mach-O 64-bit executable arm64
使用 file 命令查看 Unix 执行文件,能够看到其为 Mach-O 文件,支持 arm_v7 和 arm64 两种 CPU 指令集。Mach-O 文件格式中用来存储和处理调试信息的标准格式为 DWARF (DebuggingWith Arbitrary Record Formats
) 。
采用 sublime 打开 .app.dSYM
文件:
能看出 dSYM 文件实际上是一个文件夹,里面目录名为 DWARF
的文件夹中的文件,其格式为 Mach-O dSYM
:
file MTAppProduction.app.dSYM/Contents/Resources/DWARF/MTAppProduction
MTAppProduction (for architecture armv7): Mach-O dSYM companion file arm_v7
MTAppProduction (for architecture arm64): Mach-O 64-bit dSYM companion file arm64
文章开始所说的映射,就是在 MTAppProduction
和.app.dSYM
两者间进行的。
通过 Xcode 工具能够查看 dSYM 文件的 UUID:
xcrun dwarfdump --uuid MTAppProduction.app.dSYM
UUID: C6FF1B19-2F18-31D2-A125-2C51795EFA60 (armv7) MTAppProduction.app.dSYM/Contents/Resources/DWARF/MTAppProduction
UUID: C6E7752D-6BF6-3761-8AA8-E7E261C548C0 (arm64) MTAppProduction.app.dSYM/Contents/Resources/DWARF/MTAppProduction
不同架构下的 UUID 用于区分不同的 dSYM 匹配文件。
使用Xcode 自带的 dwarfdump
命令,对 .app.dSYM
进行信息提取:
1 获取函数文件 info 信息:
dwarfdump -p -debug-info /Users/zhudongdong/Desktop/dsym/MTAppProduction.app.dSYM/Contents/Resources/DWARF/MTAppProduction > info-e.txt
2 获取函数行号 line 信息:
dwarfdump -p --debug-line /Users/zhudongdong/Desktop/dsym/MTAppProduction.app.dSYM/Contents/Resources/DWARF/MTAppProduction > line-e.txt
取 info 信息的一段进行分析:
0x0009e61a: DW_TAG_subprogram
DW_AT_low_pc (0x0000000100072884)
DW_AT_high_pc (0x0000000100072898)
DW_AT_frame_base (DW_OP_reg31 WSP)
DW_AT_object_pointer (0x0009e63b)
DW_AT_name ("-[MTOpenEditController setProfitLossCell:]")
DW_AT_decl_file ("/Users/zhudongdong/Desktop/td/mitrade-iOS2/mitrade-iOS/MTApp/UI/Positions/Controller/PositonDetail/MTOpenEditController.m")
DW_AT_decl_line (42)
DW_AT_prototyped (0x01)
DW_AT_artificial (0x01)
DW_AT_APPLE_optimized (0x01)
在上段能够得到如下信息:
1 文件的起始地址: 0x0009e61a ;
2 方法名: -[MTOpenEditController setProfitLossCell:]
3 文件名称: MTOpenEditController.m
4 方法起始地址: 0x0000000100072884
5 方法结束地址: 0x0000000100072898
取 line 的一段信息如下:
Address Line Column File ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x00000000001f35c0 42 0 2 0 0 is_stmt
0x00000000001f35cc 45 37 2 0 0 is_stmt prologue_end
0x00000000001f3600 46 3 2 0 0 is_stmt
0x00000000001f3626 0 0 2 0 0
0x00000000001f362a 53 27 2 0 0 is_stmt
0x00000000001f362e 0 0 2 0 0
能够看到具体每一个 Address 对应的行号 ,比如 0x00000000001f35c0 对应 42 行。
一个典型的崩溃信息如下:
Incident Identifier: E8B419BB-9DAA-4523-A092-7A23C3ABDE38
CrashReporter Key: 82aa65447d853b4be824cac9d0399b86f9984329
Hardware Model: iPhone10,3
Process: WeChat [9322]
Path: /private/var/containers/Bundle/Application/6CF1E4C4-1E68-4B3E-A8CB-BD0E78A815A9/WeChat.app/WeChat
Identifier: com.tencent.xin
Version: 7.0.1.32 (7.0.1)
AppStoreTools: 10B63
AppVariant: 1:iPhone10,3:12
Code Type: ARM-64 (Native)
Role: Non UI
Parent Process: launchd [1]
Coalition: com.tencent.xin [2023]
Date/Time: 2019-03-13 18:52:00.6011 +0800
Launch Time: 2019-03-13 07:20:06.8636 +0800
OS Version: iPhone OS 12.1.4 (16D57)
Baseband Version: 3.31.00
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x408c780000000008
VM Region Info: 0x408c780000000008 is not in any region. Bytes after previous region: 4651224445287923721
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
MALLOC_NANO 0000000280000000-00000002a0000000 [512.0M] rw-/rwx SM=PRV
--->
UNUSED SPACE AT END
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [9322]
Triggered by Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 QBar 0x00000001070ee8e0 0x106f84000 + 1485024
1 QBar 0x00000001070eea0c 0x106f84000 + 1485324
2 QBar 0x00000001070d7b90 0x106f84000 + 1391504
3 QBar 0x00000001070cde60 0x106f84000 + 1351264
4 QBar 0x00000001070ccb0c 0x106f84000 + 1346316
5 dyld 0x0000000105001864 0x104fe8000 + 104548
6 dyld 0x0000000104fea784 0x104fe8000 + 10116
7 libsystem_c.dylib 0x00000001b9213ab4 0x1b91bb000 + 363188
Binary Images:
0x100014000 - 0x103c17fff WeChat arm64 <002cc9e9f70136ae8dd415849efb2cf3> /var/containers/Bundle/Application/6CF1E4C4-1E68-4B3E-A8CB-BD0E78A815A9/WeChat.app/WeChat
0x104e08000 - 0x104e9bfff zstd arm64 <1a5604b6091b39b8abfe23d284877b97> /var/containers/Bundle/Application/6CF1E4C4-1E68-4B3E-A8CB-BD0E78A815A9/WeChat.app/Frameworks/zstd.framework/zstd
从崩溃日志中能够得到:
1 app 的 UUID : Incident Identifier: E8B419BB-9DAA-4523-A092-7A23C3ABDE38
, 用于核对 dSYM 文件;
2 崩溃标记: CrashReporter Key: 82aa65447d853b4be824cac9d0399b86f9984329
;
3 app 运行时的地址和 dSYM 文件映射的地址: Binary Images: 0x100014000 - 0x103c17fff
;
4 崩溃的地址 0x408c780000000008
;
5 崩溃时的调用栈:
Thread 0 Crashed...
想要解析崩溃日志,依据以上信息,只需要两步即可完成:
1 根据 3 中的映射地址,能够在 dSYM 文件中找到对应的函数;
2 根据崩溃的具体地址,在对应的函数中找到具体的行数;
以上是解析日志信息的整体流程,具体的地址计算,都是固定的程序化,已经有人专门做好了解析的工具:dSYMTools 。
参考:
1 https://davidlii.cn/2018/07/11/dsym.html
2 https://www.jianshu.com/p/fc67f95eee41
3 https://www.jianshu.com/p/d79d5377dccf