2分で理解しないDWARF2。
せっかくなので、簡単にDWARF2について書いとく。
まず、DWARF1.1については以下が参考になる。
http://firewood.txt-nifty.com/bbc/2005/12/introduction_to.html
DWARF2も大体同じような構造をしている。compile_unitがあって、subprogramがあって、variableがある。
/* ファイル一個で DW_TAG_compile_unit */ int func() { /* 関数一個で DW_TAG_subprogram */ int a = 0; /* 変数一個で DW_TAG_variable */ int b = 0; /* 変数一個で DW_TAG_variable */ }
こんな感じ。これが、.debug_info セクションに埋まってる。
.uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) /* compile unit */ .long .Ldebug_line0 # DW_AT_stmt_list .long .Letext0 # DW_AT_high_pc .long .Ltext0 # DW_AT_low_pc .ascii "GNU C 3.4.4 (Gentoo 3.4.4-r1, ssp-3.4.4-1.0, pie-8.7.8)\0" # DW_AT_producer .byte 0x1 # DW_AT_language .ascii "target.c\0" # DW_AT_name .ascii "/home/wo/src\0" # DW_AT_comp_dir .uleb128 0x2 # (DIE (0x7f) DW_TAG_subprogram) /* 関数 */ .long 0xb3 # DW_AT_sibling .byte 0x1 # DW_AT_external .ascii "func\0" # DW_AT_name .byte 0x1 # DW_AT_decl_file .byte 0x1 # DW_AT_decl_line .long 0xb3 # DW_AT_type .long .LFB2 # DW_AT_low_pc .long .LFE2 # DW_AT_high_pc .byte 0x1 # DW_AT_frame_base .byte 0x55 # DW_OP_reg5 .uleb128 0x3 # (DIE (0x9a) DW_TAG_variable) /* 変数 */ .ascii "a\0" # DW_AT_name .byte 0x1 # DW_AT_decl_file .byte 0x2 # DW_AT_decl_line .long 0xb3 # DW_AT_type .byte 0x2 # DW_AT_location .byte 0x91 # DW_OP_fbreg .sleb128 -4 .uleb128 0x3 # (DIE (0xa6) DW_TAG_variable) /* 変数 */ .ascii "b\0" # DW_AT_name .byte 0x1 # DW_AT_decl_file .byte 0x3 # DW_AT_decl_line .long 0xb3 # DW_AT_type .byte 0x2 # DW_AT_location .byte 0x91 # DW_OP_fbreg .sleb128 -8 .byte 0x0 # end of children of DIE 0x7f /* ここまで関数 */ .uleb128 0x4 # (DIE (0xb3) DW_TAG_base_type) /* int型 */ .ascii "int\0" # DW_AT_name .byte 0x4 # DW_AT_byte_size .byte 0x5 # DW_AT_encoding .byte 0x0 # end of children of DIE 0xb /* ここまでcompile_unit */
だが、DWARF2は、DWARF1よりもファイルサイズを小さくするためか柔軟性を上げるためか、若干面倒な構造になっている。
上のデータには、長さやフォーマット等の、データの構造を示すデータが、全く無いのがわかるだろうか。ひたすらデータが埋まっているだけである。
そのデータの構造は、.debug_abbrevセクションの中に書いてある。
.section .debug_abbrev .uleb128 0x1 # (abbrev code) /* abbrev 1番目 */ .uleb128 0x11 # (TAG: DW_TAG_compile_unit) .byte 0x1 # DW_children_yes .uleb128 0x10 # (DW_AT_stmt_list) .uleb128 0x6 # (DW_FORM_data4) .uleb128 0x12 # (DW_AT_high_pc) .uleb128 0x1 # (DW_FORM_addr) .uleb128 0x11 # (DW_AT_low_pc) .uleb128 0x1 # (DW_FORM_addr) .uleb128 0x25 # (DW_AT_producer) .uleb128 0x8 # (DW_FORM_string) .uleb128 0x13 # (DW_AT_language) .uleb128 0xb # (DW_FORM_data1) .uleb128 0x3 # (DW_AT_name) .uleb128 0x8 # (DW_FORM_string) .uleb128 0x1b # (DW_AT_comp_dir) .uleb128 0x8 # (DW_FORM_string) .byte 0x0 .byte 0x0 .uleb128 0x2 # (abbrev code) /* abbrev 2番目 */ .uleb128 0x2e # (TAG: DW_TAG_subprogram) .byte 0x1 # DW_children_yes .uleb128 0x1 # (DW_AT_sibling) .uleb128 0x13 # (DW_FORM_ref4) .uleb128 0x3f # (DW_AT_external) (...省略...)
んで、.debug_infoのほうには、参照するabbrevの番号が埋めてある。
.uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit) /* 1番目のabbrevを参照 */ .long .Ldebug_line0 # DW_AT_stmt_list .long .Letext0 # DW_AT_high_pc .long .Ltext0 # DW_AT_low_pc .ascii "GNU C 3.4.4 (Gentoo 3.4.4-r1, ssp-3.4.4-1.0, pie-8.7.8)\0" # DW_AT_producer .byte 0x1 # DW_AT_language .ascii "target.c\0" # DW_AT_name .ascii "/home/wo/src\0" # DW_AT_comp_dir .uleb128 0x2 # (DIE (0x7f) DW_TAG_subprogram) /* 2番目のabbrevを参照 */ .long 0xb3 # DW_AT_sibling .byte 0x1 # DW_AT_external .ascii "func\0" # DW_AT_name .byte 0x1 # DW_AT_decl_file .byte 0x1 # DW_AT_decl_line .long 0xb3 # DW_AT_type .long .LFB2 # DW_AT_low_pc .long .LFE2 # DW_AT_high_pc .byte 0x1 # DW_AT_frame_base .byte 0x55 # DW_OP_reg5
構造が同じ場合は、abbrevは共有するらしい。
.uleb128 0x3 # (DIE (0x9a) DW_TAG_variable) /* 3番目のabbrev */ .ascii "a\0" # DW_AT_name .byte 0x1 # DW_AT_decl_file .byte 0x2 # DW_AT_decl_line .long 0xb3 # DW_AT_type .byte 0x2 # DW_AT_location .byte 0x91 # DW_OP_fbreg .sleb128 -4 .uleb128 0x3 # (DIE (0xa6) DW_TAG_variable) /* 3番目のabbrev */ .ascii "b\0" # DW_AT_name .byte 0x1 # DW_AT_decl_file .byte 0x3 # DW_AT_decl_line .long 0xb3 # DW_AT_type .byte 0x2 # DW_AT_location .byte 0x91 # DW_OP_fbreg .sleb128 -8
細かいのは仕様書とか参考にして。あと、参考にしたのは、gdbのgdb/dwarf2read.cあたり。
よって、DWARF2を読むのは、以下のような手順になる。
- .debug_abbrevを読んでおく
- .debug_info読む。
- 番号から、abbrev参照
- 参照したabbrevをもとに、いっこ読む
- くりかえす
こんな感じ。