手動解析CrashLog之——原理篇

 

接下來再說說dwarfdump、atos等解析工具是如何從符號表文件中獲取到崩潰位置信息的。一切還得從.dSYM符號表文件開始提及。算法

1、.dSYM文件的生成app

符號表文件.dSYM其實是從Mach-O文件中抽取調試信息而獲得的文件目錄,實際用於保存調試信息的問價是DWARF,其出身能夠從蘋果員工的文章《Apple’s 「Lazy」 DWARF Scheme》瞭解一二。iphone

一、Xcode自動生成工具

Xcode會在編譯工程或者歸檔時自動爲咱們生成.dSYM文件,固然咱們也能夠經過更改Xcode的若干項Build Settings來阻止它那麼幹。網站

二、手動生成ui

另外一種方式是經過命令行從Mach-O文件中手工提取,好比:spa

1prototype

$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil /Users/wangzz/Library/Developer/Xcode/DerivedData/YourApp-cqvijavqbptjyhbwewgpdmzbmwzk/Build/Products/Debug-iphonesimulator/YourApp.app/YourApp -o YourApp.dSYM命令行

生成的位置在你命令行cd進入的位置該方式經過Xcode提供的工具dsymutil,從項目編譯結果.app目錄下的Mach-O文件中提取出調試符號表文件。實際上Xcode也是經過這種方式來生成符號表文件。debug

2、DWARF簡介

DWARF(DebuggingWith Arbitrary Record Formats),是ELF和Mach-O等文件格式中用來存儲和處理調試信息的標準格式,.dSYM中真正保存符號表數據的是DWARF文件。DWARF中不一樣的數據都保存在相應的section(節)中,ELF文件裏全部的section名稱都以".debug_"開頭,以下表所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

| Section Name         | Contents                                          |

| -------------------- | ------------------------------------------------  |

| .debug_abbrev        | Abbreviations used in the .debug_info section     |

| .debug_aranges       | A mapping between memory address and compilation  |

| .debug_frame         | Call Frame Information                            |

| .debug_info          | The core DWARF data containing DIEs               |

| .debug_line          | Line Number Program                               |

| .debug_loc           | Macro descriptions                                |

| .debug_macinfo       | A lookup table for global objects and functions   |

| .debug_pubnames      | A lookup table for global objects and functions   | 

| .debug_pubtypes      | A lookup table for global types                   |

| .debug_ranges        | Address ranges referenced by DIEs                 |

| .debug_str           | String table used by .debug_info                  |

Mach-O中關於section的命名和ELF稍有區別,把名稱前的.換成了_,例如.debug_info變成了_debug_info。

3、section信息提取

保存在DAWARF中的信息是高度壓縮的,能夠經過dwarfdump命令從中提取出可讀信息。前文所述的那些section中,定位CrashLog只須要用到.debug_info和.debug_line。因爲解析出來的數據量較大,爲了方便查看,就將其保存在文本中。兩個section的數據提取方式以下:

  • .debug_info

1

$ dwarfdump -e --debug-info YourPath/YourApp.dSYM/Contents/Resources/DWARF > info-e.txt

  • .debug_line

1

$ dwarfdump -e --debug-line YourPath/YourApp.dSYM/Contents/Resources/DWARF > line-e.txt

命令中的-e能夠增長解析結果的可讀性;其它section的提取方式相似,詳情請參考dwarfdump命令幫助信息。

4、解析崩潰地址

一、計算崩潰地址對應符號表中的地址

在上篇文章中,介紹瞭如何根據崩潰地址計算獲得對應符號表中的地址,並獲得了最終數值:0x52846,接下來咱們就經過這個值來介紹dwarfdump、atos等工具是如何解析崩潰日誌的。

二、解析過程

  • .debug_info

.debug_info中最基本的描述單元爲DIE(Debug Information Entry),詳情請參考DWARF官方網站,首先咱們要根據符號表崩潰地址0x52846從.debug_info中取出包含這個地址的DIE單元。爲了簡單起見,直接貼出了從info-e.txt中取出的對應DIE,其部份內容以下:

1

2

3

4

5

6

7

8

9

10

0x00062112:     function [99] *

                low pc( 0x000502e0 )

                high pc( 0x00053730 )

                frame base( r7 )

                object pointer( {0x0006212a} )

                name( "-[OBDFirstConnectViewController showOilPricePickerView]" )

                decl file( "/YourSourcePath/OBDFirstConnectViewController.m" )

                decl line( 870 )

                prototyped( 0x01 )

                APPLE instruction set architecture( 0x01 )

能夠看出,該DIE包含是方法-[OBDFirstConnectViewController showOilPricePickerView]的內容,其地址範圍是0x000502e0–0x00053730,咱們的目標地址0x52846正是在這個範圍內,因此能夠斷定崩潰發生在該方法的某一行中。

須要指出的是,上面這段DIE是我爲了介紹方便直接貼出來的,實際應用的時候須要經過搜索算法找出包含目標符號表崩潰地址(這裏是0x52846)的DIE。

從上述DIE中咱們能夠獲取到這些信息:

1

2

3

崩潰所在源碼文件:/YourSourcePath/OBDFirstConnectViewController.m

發生崩潰的方法:-[OBDFirstConnectViewController showOilPricePickerView]

發生崩潰的方法在源文件中的行號:870

  • . debug_line

截止目前,咱們能夠獲取到發生了崩潰的方法的相關信息,但要想肯定崩潰發生的具體行號,還須要.debug_line的幫助。

.debug_line以一個方法爲基本塊,急了該方法中每一行對應的符號表地址。經過.debug_info得知崩潰發生的方法地址範圍是0x000502e0–0x00053730,經過起始地址0x000502e0在解析. debug_line獲得的line-e.txt中直接搜索便可獲得崩潰所在方法的. debug_line數據,其中部份內容以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

0x00000000000502e0    870 /YourSourcePath/OBDFirstConnectViewController.m

0x00000000000502e0      0

0x00000000000502f0    872

0x000000000005033c    873

0x0000000000050374    874

0x000000000005039e    875

0x00000000000503c8    876

...

0x0000000000052812    880

0x000000000005283e    881

0x0000000000052846    882

0x00000000000528c8    883

...

. debug_line段的第一行內容標識了該方法的起始符號表地址,行號及方法所在文件路徑,經過以前獲得的崩潰地址0x52846便可得知崩潰發生在882行。

至此咱們已經根據崩潰地址解析出了崩潰發生位置的詳細信息:

1

2

3

4

崩潰所在源碼文件:/YourSourcePath/OBDFirstConnectViewController.m

發生崩潰的方法:-[OBDFirstConnectViewController showOilPricePickerView]

發生崩潰的方法在源文件中的行號:870

崩潰發生在源文件中得行號:882

相關文章
相關標籤/搜索