iOS开发-手动解析崩溃日志 Crash Log

一、 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.

你可能感兴趣的:(iOS开发-手动解析崩溃日志 Crash Log)