一、 dSYM文件
.dSYM(debugging SYMbols)
又稱爲調試符號表,是起源於貝爾實驗室的DWARF(Debugging With Attributed Record Formats)
.
二、dSYM文件和Crash Log一致性
二者的對應關係可以通過UUID來確定。
1、從崩潰日誌中獲取UUID
崩潰日誌有個Binary Images模塊
Binary Images:
0x100e30000 - 0x106983fff XXXXAPP arm64-unknown <3671a0be1d663f4789dbfeb9190fdacf> /var/containers/Bundle/Application/643F8D1D-9000-4211-8DA0-0C2D42DB03C4/XXXXAPP.app/XXXXAPP
0x181bee000 - 0x181c72fff IOKit arm64-unknown <54433b44779d39378d0789a4017a2948> /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit
0x181f0e000 - 0x1822bcfff CFNetwork arm64-unknown /System/Library/Frameworks/CFNetwork.framework/CFNetwork
0x188503000 - 0x189081fff JavaScriptCore arm64-unknown <8be29f5ee31a302bbc16e47869e799ac> /System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
0x181845000 - 0x181bdbfff CoreFoundation arm64-unknown <533c841ed6e9313d8adb02388744e2ef> /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
0x1839de000 - 0x183f8efff ImageIO arm64-unknown <728aeffd50883729bc1ac09900f05cf2> /System/Library/Frameworks/ImageIO.framework/ImageIO
0x18323e000 - 0x183785fff CoreGraphics arm64-unknown <59a6f76dbc9f3e44bdf30351088b637d> /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics
0x1872c6000 - 0x1873bcfff AVFAudio arm64-unknown /System/Library/Frameworks/AVFoundation.framework/Frameworks/AVFAudio.framework/AVFAudio
0x18131d000 - 0x18139afff libsystem_c.dylib arm64-unknown <61d2e950add73139aea459b55997ea48> /usr/lib/system/libsystem_c.dylib
0x18382b000 - 0x18383efff GraphicsServices arm64-unknown <5011ec2511d73a56af501e8207d54962> /System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices
0x18127b000 - 0x1812e0fff libdispatch.dylib arm64-unknown <0c931ac760133de187bb6f440beed5eb> /usr/lib/system/libdispatch.dylib
0x189ad3000 - 0x18b1a5fff WebCore arm64-unknown <2fe4173593ba35c4a5e04b40b40f1a7e> /System/Library/PrivateFrameworks/WebCore.framework/WebCore
0x182a6d000 - 0x182a77fff IOSurface arm64-unknown <1f24b80565013f8d94b5e18c144f24bc> /System/Library/Frameworks/IOSurface.framework/IOSurface
EOF
從中可以看到若干信息:
代碼段的起終地址爲:0x100e30000 - 0x106983fff
運行你應用的CPU指令集爲:arm64
應用的UUID爲:3671a0be1d663f4789dbfeb9190fdacf(不區分大小寫)
2、從符號表中獲取UUID
執行以下命令從符號表中提取UUID:
user$ dwarfdump --uuid xxx.dSYM
//或者命令dwarfdump --uuid xxx.dSYM/Contents/Resources/DWARF/xxx
UUID: 815AF08E-2A1E-359C-9082-7C98326D51F4 (armv7) xxx.dSYM/Contents/Resources/DWARF/xxx
UUID: 3671A0BE-1D66-3F47-89DB-FEB9190FDACF (arm64) xxx.dSYM/Contents/Resources/DWARF/xxx
得到armv7指令集的UUID爲:815AF08E-2A1E-359C-9082-7C98326D51F4
得到arm64指令集的UUID爲:3671A0BE-1D66-3F47-89DB-FEB9190FDACF
(如果你的二進制文件支持多個指令集,這裏會列出每個指令集對應符號表的UUID),通過和崩潰日誌中的對比發現二者一致,纔可進行進一步的解析操作。
三、計算崩潰符號表地址
Thread 0 Lagged:
0 libsystem_kernel.dylib 0x1813efde8 0x1813ef000 + _mach_msg_trap
1 libsystem_kernel.dylib 0x1813efc60 0x1813ef000 + _mach_msg
2 IOKit 0x181c57bb8 0x181bee000 + _io_connect_method
3 IOKit 0x181bf4038 0x181bee000 + _IOConnectCallMethod
4 IOSurface 0x182a71f9c 0x182a6d000 + _IOSurfaceClientWrapClientImage
5 IOSurface 0x182a7545c 0x182a6d000 + _IOSurfaceWrapClientImage
6 ImageIO 0x183aa8c78 0x1839de000 + __Z34IIO_CreateImageIOSurfaceWithFormatmmmj
7 ImageIO 0x183a312d8 0x1839de000 + __ZN14JPEGReadPlugin37createImageBlockSetWithHardware_aspenEP7InfoRecP15CGImageProviderPK8__CFData6CGSizePb
8 ImageIO 0x183b8cfc8 0x1839de000 + __ZN19AppleJPEGReadPlugin37createImageBlockSetWithHardwareDecodeEP7InfoRecP15CGImageProvider6CGSizePb
9 ImageIO 0x183b8c8b0 0x1839de000 + __ZN19AppleJPEGReadPlugin17copyImageBlockSetEP7InfoRecP15CGImageProvider6CGRect6CGSizePK14__CFDictionary
10 ImageIO 0x183b8b690 0x1839de000 + __ZN19AppleJPEGReadPlugin21CopyImageBlockSetProcEPvP15CGImageProvider6CGRect6CGSizePK14__CFDictionary
11 ImageIO 0x183a13684 0x1839de000 + __ZN20IIOImageProviderInfo28copyImageBlockSetWithOptionsEP15CGImageProvider6CGRect6CGSizePK14__CFDictionary
12 ImageIO 0x183a10e98 0x1839de000 + __ZN20IIOImageProviderInfo28CopyImageBlockSetWithOptionsEPvP15CGImageProvider6CGRect6CGSizePK14__CFDictionary
13 CoreGraphics 0x18341d360 0x18323e000 + _img_blocks_create
14 CoreGraphics 0x183424b8c 0x18323e000 + _img_data_lock
15 CoreGraphics 0x183424444 0x18323e000 + _CGSImageDataLock
16 CoreGraphics 0x183242440 0x18323e000 + _ripc_AcquireRIPImageData
17 CoreGraphics 0x183438f5c 0x18323e000 + _ripc_DrawImage
18 CoreGraphics 0x183428de8 0x18323e000 + _CGContextDrawImageWithOptions
19 xxx 0x100ec4040 0x100e30000 + 606272
20 xxx 0x100eb3868 0x100e30000 + 538728
21 xxx 0x100ec9a70 0x100e30000 + 629360
22 xxx 0x100eca478 0x100e30000 + 631928
23 xxx 0x100f47dd8 0x100e30000 + 1146328
24 xxx 0x101698d10 0x100e30000 + 8817936
25 xxx 0x1016bcf54 0x100e30000 + 8965972
26 libdispatch.dylib 0x18127caa0 0x18127b000 + __dispatch_call_block_and_release
27 libdispatch.dylib 0x18127ca60 0x18127b000 + __dispatch_client_callout
28 libdispatch.dylib 0x18128949c 0x18127b000 + __dispatch_main_queue_callback_4CF$VARIANT$mp
29 CoreFoundation 0x181933070 0x181845000 + ___CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
30 CoreFoundation 0x181930bc8 0x181845000 + ___CFRunLoopRun
31 CoreFoundation 0x181850da8 0x181845000 + _CFRunLoopRunSpecific
32 GraphicsServices 0x183836020 0x18382b000 + _GSEventRunModal
33 UIKit 0x18b870758 0x18b553000 + _UIApplicationMain
34 xxx 0x100e3413c 0x100e30000 + 16700
35 libdyld.dylib 0x1812e1fc0 0x1812e1000 + _start
1、符號表堆棧地址計算方式
要想利用符號表解析出崩潰對應位置,需要計算出符號表中對應的崩潰堆棧地址。
而從上述堆棧中第19行可以看到,應用崩潰發生在運行時地址0x100ec4040
,該進程的運行時起始地址是0x100e30000
,崩潰處距離進程起始地址的偏移量爲十進制的606272(對應十六進制爲0x94040)
。
三者對應關係:
0x100ec4040 = 0x100e30000 + 0x94040
對應的公式爲:
運行時堆棧地址 = 運行時起始地址 + 偏移量
崩潰堆棧中的起始地址和崩潰地址均爲運行時地址,根據虛擬內存偏移量不變原理,只要提供了符號表TEXT段的起始地址,再加上偏移量(這裏爲0x94040)就能得到符號表中的堆棧地址,即:
符號表堆棧地址 = 符號表起始地址 + 偏移量
2、獲取符號表中的TEXT段起始地址
執行命令
otool -l xxx.dSYM/Contents/Resources/DWARF/xxx
Load command 0
cmd LC_UUID
cmdsize 24
uuid 815AF08E-2A1E-359C-9082-7C98326D51F4
Load command 1
cmd LC_SYMTAB
cmdsize 24
symoff 8192
nsyms 475187
stroff 5710436
strsize 18159960
Load command 2
cmd LC_SEGMENT
cmdsize 56
segname __PAGEZERO
vmaddr 0x00000000
vmsize 0x00004000
fileoff 0
filesize 0
maxprot 0x00000000
initprot 0x00000000
nsects 0
flags 0x0
Load command 3
cmd LC_SEGMENT
cmdsize 940
segname __TEXT
vmaddr 0x00004000
vmsize 0x053e4000
fileoff 0
filesize 0
maxprot 0x00000005
initprot 0x00000005
nsects 13
flags 0x0
segname __TEXT
vmaddr 0x00004000
即爲TEXT段的起始地址
3、計算符號表地址
由公式:
符號表堆棧地址 = 符號表起始地址 + 偏移量
可得:
0x98040 = 0x94040 + 0x4000
即符號表中的崩潰地址爲0x98040
,接下來就可以根據這個地址解析出崩潰位置了。
四、崩潰信息還原
1、dwarfdump命令
dwarfdump --lookup 0x98040 --arch armv7 xxx.dSYM/
也可以使用:
dwarfdump --arch armv7 xxx.dSYM --lookup 0x98040 | grep 'Line table'
輸出結果如下
----------------------------------------------------------------------
File: xxx.dSYM/Contents/Resources/DWARF/xxx (armv7)
----------------------------------------------------------------------
Looking up address: 0x0000000000098040 in .debug_info... found!
0x00091812: Compile Unit: length = 0x000051dd version = 0x0002 abbr_offset = 0x00000000 addr_size = 0x04 (next CU at 0x000969f3)
0x0009181d: TAG_compile_unit [127] *
AT_producer( "Apple LLVM version 9.1.0 (clang-902.0.39.1)" )
AT_language( DW_LANG_ObjC )
AT_name( "/Users/xxx/xxx/xxController.m" )
AT_stmt_list( 0x00041b6c )
AT_comp_dir( "/Users/xxx/Pods" )
AT_APPLE_major_runtime_vers( 0x02 )
AT_low_pc( 0x00095394 )
AT_high_pc( 0x0009bcf8 )
0x00094a3f: TAG_subprogram [178] *
AT_low_pc( 0x00098036 )
AT_high_pc( 0x00098056 )
AT_frame_base( r7 )
AT_name( "__copy_helper_block_" )
AT_decl_file( "/Users/xx/xxxController.m" )
AT_decl_line( 185 )
AT_APPLE_isa( 0x01 )
Line table dir : '/Users/xxxController.m' line 176, column 74 with start address 0x0000000000098040
Looking up address: 0x0000000000098040 in .debug_frame... not found.
編譯時文件目錄,崩潰發生的文件名稱以及文件中具體行號等信息,這些信息就能準確定位崩潰原因。
2、atos命令
atos是另一種更加簡潔的崩潰日誌解析方法,使用方式如下:
$atos -o LuBao -arch armv7 0x98040
相對dwarfdump命令的解析結果,更加簡潔直觀的指出了崩潰發生的位置。
3、無需符號表崩潰地址的解析方式
實際上,atos還提供了另外一種無需計算崩潰地址對應的符號表地址的方式,命令格式如下:
$atos -o xxx.dSYM/Contents/Resources/DWARF/xxx -arch armv7 -l 0x100e30000 0x100ec4040
其中-l選項指定了二進制文件在運行時的起始地址0x100e30000(獲取方式見Binary Images相關內容),後面跟的是崩潰發生的運行時地址0x100ec4040.