dwarf调试信息格式入门
生活随笔
收集整理的這篇文章主要介紹了
dwarf调试信息格式入门
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
https://www.prevanders.net/dwarf.html#testingcomment http://www.dwarfstd.org/ http://www.cnblogs.com/zqingnn/archive/2011/01/05/1926384.html
一個(gè)程序的完成過(guò)程一般是編碼、編譯、運(yùn)行的過(guò)程,當(dāng)然這是一個(gè)理想的過(guò)程,所有的開發(fā)幾乎都不可能是一帆風(fēng)順的,總會(huì)有些意想不到的錯(cuò)誤,這時(shí)便需要調(diào)試,良好的調(diào)試器應(yīng)該每一個(gè)程序員的必備。
那么調(diào)試器使用的調(diào)試信息是從哪里來(lái)的呢?答案簡(jiǎn)單的很,是從編譯后的文件中來(lái)的(注意這里編譯的時(shí)候要使用特定的編譯選項(xiàng),如VC使用debug模式,GCC使用”-g”)。在編譯的時(shí)候,編譯器會(huì)從源文件中收集大量的信息,例如變量名、變量類型、變量所在行號(hào)、函數(shù)名、函數(shù)參數(shù)、函數(shù)的地址范圍、行號(hào)和地址的對(duì)應(yīng)關(guān)系等等,然后按照一種特定的格式寫入到編譯后的文件中。調(diào)試的時(shí)候,調(diào)試器便從文件中讀取并解析這些信息,以產(chǎn)生人們可讀性比較強(qiáng)的信息。簡(jiǎn)單的說(shuō),調(diào)試信息就是在機(jī)器碼和對(duì)應(yīng)的源代碼之間建立一座橋梁,大大方便和提高了調(diào)試程序的能力。
調(diào)試信息一般都是按照什么樣的格式存放的呢?主要有下面幾種:stabs,COFF,PE-COFF,OMF,IEEE-695和DWARF。其中DWARF在Linux中被普遍使用,我們主要分析它。
DWARF的全稱是"Debugging With Attributed Record Formats",遵從GNU FDL授權(quán)。現(xiàn)在已經(jīng)有dwarf1,dwarf2,dwarf3三個(gè)版本。
Dwarf最初被貝爾實(shí)驗(yàn)室設(shè)計(jì)用來(lái)供Unix System V的sdb調(diào)試器使用,并且在1989年被Unix國(guó)際化部門的PLSIG (Programming Languages Special Interest Group)標(biāo)準(zhǔn)化成為dwarf1.0。但是dwarf1有著很多明顯的缺點(diǎn),于是PLSIG繼續(xù)開發(fā),改正了缺點(diǎn),并加入了對(duì)C++等語(yǔ)言的支持,并在1990年正式公布了dwarf2的標(biāo)準(zhǔn)草案。但是稍后由于一些原因,PLSIG被解散,dwarf的開發(fā)陷入到多個(gè)并不合作的組織中間,造成dwarf2的一些實(shí)現(xiàn)細(xì)節(jié)要取決于特定的編譯器。這種情況一直持續(xù)到1999年,開發(fā)工作受到了來(lái)自實(shí)現(xiàn)對(duì)HP/Inter IA-64架構(gòu)提供較好支持的推動(dòng),成立了dwarf委員會(huì),dwarf的原作者擔(dān)任負(fù)責(zé)人,
開始了dwarf3的開發(fā),并于2006年1月份推出dwarf3.0,同時(shí)為了解決分歧,dwarf委員會(huì)加入了自由標(biāo)準(zhǔn)組織,在自由標(biāo)準(zhǔn)組織與來(lái)自Linux基金會(huì)的OSDL(Open Source Development Labs)合并后,dwarf重返獨(dú)立狀態(tài)并創(chuàng)建了自己的網(wǎng)站:dwarfstd.org。
這三個(gè)版本中,dwarf2對(duì)dwarf1的改變很大,dwarf3大多是對(duì)dwarf2的擴(kuò)充。
現(xiàn)在dwarf已經(jīng)是一種獨(dú)立的標(biāo)準(zhǔn),可以支持C、C++、JAVA、Fortran等語(yǔ)言。
在了解了dwarf的歷史之后,來(lái)看一下如何查看dwarf所包含的調(diào)試信息內(nèi)容,并在下一篇文章中介紹這些內(nèi)容的具體意思。查看內(nèi)容的工具常用的有四種:
1. readelf
GNU提供的二進(jìn)制工具,功能很多,并不限于讀dwarf信息
2. gdb
這個(gè)就不用多說(shuō)了吧,^_^
3. drawfdump
是一個(gè)被打包在libdwarf內(nèi)的程序
4. libdwarf
是一個(gè)封裝好的C庫(kù)API,用來(lái)讀取dwarf信息
在這里我們主要使用readelf工具。
先寫一個(gè)簡(jiǎn)單的C程序,如下:
1: 2: int add(int, int); 3: 4: int main() 5: ...{ 6: int i, j; 7: 8: for(i = 0; i < 100; i += 5, j = i * 5) 9: add(i, j); 10: 11: return 0; 12: } 13: 14: int add(int a, int b) 15: ...{ 16: return a + b; 17: }?
然后使用gcc –g hello.c –o hello編譯。生成hello文件。
Hello文件是elf格式的,elf一般由多個(gè)節(jié)(section)組成,不熟悉的可以看前面兩篇關(guān)于elf文件格式的文章。調(diào)試信息被包含在某幾個(gè)節(jié)中,如果是用dwarf2格式編譯的,這些節(jié)的名字一般是以.debug開頭,如.debug_info,.debug_line,.debug_frame等,如果是用dwarf1格式編譯的,這些節(jié)的名字一般是.debug,.line等?,F(xiàn)在的編譯器默認(rèn)大多數(shù)是dwarf2格式編譯,當(dāng)然可以通過(guò)gcc的編譯選項(xiàng)改變。
現(xiàn)在來(lái)看hello文件都包含了哪些調(diào)試信息。
首先來(lái)看都包含了哪些調(diào)試節(jié),使用readelf –S hello命令,產(chǎn)生如下輸出(已刪一些無(wú)關(guān)內(nèi)容):
[Nr] Name Type Addr Off Size [ 0] NULL 00000000 000000 000000 [ 1] .text PROGBITS 00008000 008000 0006c4 [ 2] .ARM.exidx ARM_EXIDX 000086c4 0086c4 000008 [ 3] .data PROGBITS 000086d0 0086d0 000520 [ 4] .bss NOBITS 00008bf0 008bf0 000020 [ 5] .debug_aranges PROGBITS 00000000 008bf0 000020 [ 6] .debug_pubnames PROGBITS 00000000 008c10 000023 [ 7] .debug_info PROGBITS 00000000 008c33 0000cc [ 8] .debug_abbrev PROGBITS 00000000 008cff 00006b [ 9] .debug_line PROGBITS 00000000 008d6a 00003e [10] .debug_frame PROGBITS 00000000 008da8 000188 [11] .debug_loc PROGBITS 00000000 008f30 000054 [12] .ARM.attributes ARM_ATTRIBUTES 00000000 008f84 000010 [13] .comment PROGBITS 00000000 008f94 000032 [14] .shstrtab STRTAB 00000000 008fc6 0000ad [15] .symtab SYMTAB 00000000 00931c 000780 [16] .strtab STRTAB 00000000 009a9c 000416?
可見一共包含了17個(gè)節(jié),其中7個(gè)調(diào)試信息的節(jié)。
在來(lái)看一下各個(gè)調(diào)試信息節(jié)包含的內(nèi)容,使用readelf –w* hello命令,*是調(diào)試節(jié)名的第一個(gè)字母,如-wi就是查看.debug_info節(jié)的內(nèi)容,-wl就是查看.debug_line節(jié)的內(nèi)容。
對(duì)于一個(gè)調(diào)試文件,.debug_info和.debug_line節(jié)是必須有的,其他的不見得。同時(shí)也可以自己寫鏈接腳本實(shí)現(xiàn)對(duì)所有節(jié)(不局限于調(diào)試節(jié))的控制,如指定每個(gè)節(jié)的基址等。
.debug_info基本包含了一個(gè)源文件內(nèi)部的大部分信息,如函數(shù)、參數(shù)、變量、類型等等,我們看一下它的輸出:
The section .debug_info contains: Compilation Unit @ offset 0x0: Length: 200 Version: 2 Abbrev Offset: 0 Pointer Size: 4 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit) DW_AT_stmt_list : 0 DW_AT_high_pc : 0x8248 DW_AT_low_pc : 0x81ac DW_AT_producer : GNU C 4.1.1 DW_AT_language : 1 (ANSI C) DW_AT_name : hello.c DW_AT_comp_dir : C:\Program Files\CodeSourcery\Sourcery G++\bin <1><5c>: Abbrev Number: 2 (DW_TAG_subprogram) DW_AT_sibling : <92> DW_AT_external : 1 DW_AT_name : main DW_AT_decl_file : 1 DW_AT_decl_line : 5 DW_AT_type : <92> DW_AT_low_pc : 0x81ac DW_AT_high_pc : 0x8214 DW_AT_frame_base : 0 (location list) <2><79>: Abbrev Number: 3 (DW_TAG_variable) DW_AT_name : i DW_AT_decl_file : 1 DW_AT_decl_line : 6 DW_AT_type : <92> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24) <2><85>: Abbrev Number: 3 (DW_TAG_variable) DW_AT_name : j DW_AT_decl_file : 1 DW_AT_decl_line : 6 DW_AT_type : <92> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) <1><92>: Abbrev Number: 4 (DW_TAG_base_type) DW_AT_name : int DW_AT_byte_size : 4 DW_AT_encoding : 5 (signed) <1><99>: Abbrev Number: 5 (DW_TAG_subprogram) DW_AT_external : 1 DW_AT_name : add DW_AT_decl_file : 1 DW_AT_decl_line : 15 DW_AT_prototyped : 1 DW_AT_type : <92> DW_AT_low_pc : 0x8214 DW_AT_high_pc : 0x8248 DW_AT_frame_base : 0x2a (location list) <2><b2>: Abbrev Number: 6 (DW_TAG_formal_parameter) DW_AT_name : a DW_AT_decl_file : 1 DW_AT_decl_line : 14 DW_AT_type : <92> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) <2><be>: Abbrev Number: 6 (DW_TAG_formal_parameter) DW_AT_name : b DW_AT_decl_file : 1 DW_AT_decl_line : 14 DW_AT_type : <92> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24) ?.debug_line包含了所有地址和源文件行的對(duì)應(yīng)信息,內(nèi)容如下:
??
?
Dump of debug contents of section .debug_line: Length: 58 DWARF Version: 2 Prologue Length: 30 Minimum Instruction Length: 2 Initial value of 'is_stmt': 1 Line Base: -5 Line Range: 14 Opcode Base: 13 Opcodes: Opcode 1 has 0 args Opcode 2 has 1 args Opcode 3 has 1 args Opcode 4 has 1 args Opcode 5 has 1 args Opcode 6 has 0 args Opcode 7 has 0 args Opcode 8 has 0 args Opcode 9 has 1 args Opcode 10 has 0 args Opcode 11 has 0 args Opcode 12 has 1 args The Directory Table is empty. The File Name Table: Entry Dir Time Size Name 1 0 0 0 hello.c Line Number Statements: Extended opcode 2: set Address to 0x81ac Special opcode 9: advance Address by 0 to 0x81ac and Line by 4 to 5 Special opcode 120: advance Address by 16 to 0x81bc and Line by 3 to 8 Special opcode 90: advance Address by 12 to 0x81c8 and Line by 1 to 9 Special opcode 88: advance Address by 12 to 0x81d4 and Line by -1 to 8 Advance PC by constant 34 to 0x81f6 Special opcode 78: advance Address by 10 to 0x8200 and Line by 3 to 11 Special opcode 34: advance Address by 4 to 0x8204 and Line by 1 to 12 Special opcode 120: advance Address by 16 to 0x8214 and Line by 3 to 15 Special opcode 174: advance Address by 24 to 0x822c and Line by 1 to 16 Special opcode 90: advance Address by 12 to 0x8238 and Line by 1 to 17 Advance PC by 16 to 0x8248 Extended opcode 1: End of Sequence總結(jié)
以上是生活随笔為你收集整理的dwarf调试信息格式入门的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: node.js博客GitHub搭建(he
- 下一篇: dedecms的自定义模块