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

細かいのは仕様書とか参考にして。あと、参考にしたのは、gdbgdb/dwarf2read.cあたり。



よって、DWARF2を読むのは、以下のような手順になる。

  1. .debug_abbrevを読んでおく
  2. .debug_info読む。
  3. 番号から、abbrev参照
  4. 参照したabbrevをもとに、いっこ読む
  5. くりかえす

こんな感じ。