美文网首页
iOS开发-手动解析崩溃日志 Crash Log

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

作者: Pandakingli | 来源:发表于2018-09-06 00:30 被阅读0次

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

          本文链接:https://www.haomeiwen.com/subject/bqftgftx.html