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