DWARFという、実行ファイル内のデータには、デバッグに必要なさまざまな情報を書いてあるデータが書いてあって、それらはELFセクションとの関係に書いた通り、UNIXの実行ファイル形式ELFの「セクション」内に「.debug_xxxx」なセクション名でいろいろ書かれているんだよって、書きましたが。。。。
実は、この最大全部で11あるセクションのうち、".debug_line"、".debug_frame"、".debug_macinfo"の3つ以外は、全部ここに書く".debug_abbrev"、".debug_info"セクションで表される「デバッグ情報」と、この「デバッグ情報」を補助するための子分セクションです。
つまり、デバッガが必要とするデバッグ用の情報のうち、ほとんどはこの「デバッグ情報」に書かれています!
つーじょう、こいつだけ読みさえすれば、「ソース行番号とアセンブラコードアドレスの関係」「今実行中の関数の開始アドレスと、呼び出した関数の情報(スタックトレース用の情報)」以外のほぼ全てが手に入ります。
じゃ、どんな情報があるのか?以下、一例ですが、ざっと上げてみます。(あ、ちなみにこれ以外もいろいろあります。そのうち、一覧で並べますです)
などなど。
あと、この中で例えば「enum型の名前」なんて物はソース解析すりゃわかんじゃん、となりますが、DWARFはC/C++/JAVA/Fortran/PASCAL/ObjectCに加え、なんとAdaやPL/I、Modula2、Dまでサポート扱いです!それどころか、メーカーが勝手!に作った言語まで、コンパイラが適切にDWARF吐いてくれたら対応できますよーに、ということを想定して作られているので、デバッガがいちいち言語毎にソース解析ロジックを持たなくても最低限度済むよう、こういった情報まで持っています。
(なので、パソコンはもちろん、ボーイング777やF22からスパコン、IBMメインフレームまでデバッグできるみたいです。。。にしてもCOBOLがないのはなんでだろ〜)
※あ、あと以下では、これらの情報のことをまとめて「デバッグ情報」ってよびますです。
この「デバッグ情報」ですが、まともに、というか、何にも考えずにそのまんま突っ込もうとすると、ベラボウなデータ量になってしまうようなので、データ量を削減する工夫として、以下2種類の情報に分けて格納するようにしています。
例えば、C言語の「関数」に関するデバッグ情報があったとします。このとき、以下の様に「データ格納構造」と「実際のデータ」に分けることができます。
そして、C言語では、一般に関数ってもんはめちゃくちゃ数があります。ただし、上の、関数のデバッグ情報の「データ格納構造」は、ほとんどのケースで、おんなじデータ格納構造が使いまわせそうですね。
ということで、データ量の削減が第一!とするDWARF君では、上記の例のように「データ格納構造」と「実際のデータ」を分割し、「データ格納構造」は使い廻すことで、データ量の削減をはかっています。
そして、この「データ格納構造」「実際のデータ」別に、以下のセクションに情報を分割して書く仕様になっています。
んで、これ以上は、ぐちゃぐちゃ書くよりも実際のデータ見た方が、分かりやすい、ので、以下実機データです。
まず、サンプル(いけにえ)のC言語ソースです。
#include<stdio.h> int a; void func2( int *b ) { *b = 3; return; } int func1( int a, int *b) { int c; func2( b ); c = a + *b; return c; } int main( int argc, char *argv[]) { int b; int c; a = 1; c = func1( a, &b ); printf("a=%d, b=%d, c=%d\n", a, b, c); return; }
さて、このイケニエ君ソースを、
gcc -o test -g main.cで、デバッグ情報を付けてね、ってちゅーもん付きでコンパイルして、作ってくれた実行ファイルを
readelf -w testなおまじない!をもって、吐かせた.debug_abbrevと.debug_infoの解析結果を、以下はっちゃいます。
1 Contents of the .debug_abbrev section: 2 3 Number TAG 4 1 DW_TAG_compile_unit [has children] 5 DW_AT_producer DW_FORM_string 6 DW_AT_language DW_FORM_data1 7 DW_AT_name DW_FORM_string 8 DW_AT_comp_dir DW_FORM_string 9 DW_AT_low_pc DW_FORM_addr 10 DW_AT_high_pc DW_FORM_addr 11 DW_AT_stmt_list DW_FORM_data4 12 2 DW_TAG_base_type [no children] 13 DW_AT_byte_size DW_FORM_data1 14 DW_AT_encoding DW_FORM_data1 15 DW_AT_name DW_FORM_string 16 3 DW_TAG_base_type [no children] 17 DW_AT_byte_size DW_FORM_data1 18 DW_AT_encoding DW_FORM_data1 19 4 DW_TAG_pointer_type [no children] 20 DW_AT_byte_size DW_FORM_data1 21 DW_AT_type DW_FORM_ref4 22 5 DW_TAG_subprogram [has children] 23 DW_AT_external DW_FORM_flag 24 DW_AT_name DW_FORM_string 25 DW_AT_decl_file DW_FORM_data1 26 DW_AT_decl_line DW_FORM_data1 27 DW_AT_prototyped DW_FORM_flag 28 DW_AT_low_pc DW_FORM_addr 29 DW_AT_high_pc DW_FORM_addr 30 DW_AT_frame_base DW_FORM_data4 31 DW_AT_sibling DW_FORM_ref4 32 6 DW_TAG_formal_parameter [no children] 33 DW_AT_name DW_FORM_string 34 DW_AT_decl_file DW_FORM_data1 35 DW_AT_decl_line DW_FORM_data1 36 DW_AT_type DW_FORM_ref4 37 DW_AT_location DW_FORM_block1 38 7 DW_TAG_subprogram [has children] 39 DW_AT_external DW_FORM_flag 40 DW_AT_name DW_FORM_string 41 DW_AT_decl_file DW_FORM_data1 42 DW_AT_decl_line DW_FORM_data1 43 DW_AT_prototyped DW_FORM_flag 44 DW_AT_type DW_FORM_ref4 45 DW_AT_low_pc DW_FORM_addr 46 DW_AT_high_pc DW_FORM_addr 47 DW_AT_frame_base DW_FORM_data4 48 DW_AT_sibling DW_FORM_ref4 49 8 DW_TAG_variable [no children] 50 DW_AT_name DW_FORM_string 51 DW_AT_decl_file DW_FORM_data1 52 DW_AT_decl_line DW_FORM_data1 53 DW_AT_type DW_FORM_ref4 54 DW_AT_location DW_FORM_block1 55 9 DW_TAG_variable [no children] 56 DW_AT_name DW_FORM_string 57 DW_AT_decl_file DW_FORM_data1 58 DW_AT_decl_line DW_FORM_data1 59 DW_AT_type DW_FORM_ref4 60 DW_AT_external DW_FORM_flag 61 DW_AT_location DW_FORM_block1
1 The section .debug_info contains: 2 3 Compilation Unit @ offset 0x0: 4 Length: 510 5 Version: 2 6 Abbrev Offset: 0 7 Pointer Size: 8 8 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit) 9 < c> DW_AT_producer : GNU C 4.2.1 20070831 patched [FreeBSD] 10 <33> DW_AT_language : 1 (ANSI C) 11 <34> DW_AT_name : main.c 12 <3b> DW_AT_comp_dir : /work/test/dwarftest2 13 <55> DW_AT_low_pc : 0x4005b0 14 <5d> DW_AT_high_pc : 0x400648 15 <65> DW_AT_stmt_list : 0 16 <1><69>: Abbrev Number: 2 (DW_TAG_base_type) 17 <6a> DW_AT_byte_size : 1 18 <6b> DW_AT_encoding : 6 (signed char) 19 <6c> DW_AT_name : signed char 20 <一部、はしょってます> 21 <1><ac>: Abbrev Number: 2 (DW_TAG_base_type) 22 <ad> DW_AT_byte_size : 4 23 <ae> DW_AT_encoding : 5 (signed) 24 <af> DW_AT_name : int 25 <一部、はしょってます> 26 <1><f7>: Abbrev Number: 3 (DW_TAG_base_type) 27 <f8> DW_AT_byte_size : 8 28 <f9> DW_AT_encoding : 7 (unsigned) 29 <一部、はしょってます> 30 <1><102>: Abbrev Number: 4 (DW_TAG_pointer_type) 31 <103> DW_AT_byte_size : 8 32 <104> DW_AT_type : <fa> 33 <1><108>: Abbrev Number: 5 (DW_TAG_subprogram) 34 <109> DW_AT_external : 1 35 <10a> DW_AT_name : func2 36 <110> DW_AT_decl_file : 1 37 <111> DW_AT_decl_line : 6 38 <112> DW_AT_prototyped : 1 39 <113> DW_AT_low_pc : 0x4005b0 40 <11b> DW_AT_high_pc : 0x4005c4 41 <123> DW_AT_frame_base : 0 (location list) 42 <127> DW_AT_sibling : <138> 43 <2><12b>: Abbrev Number: 6 (DW_TAG_formal_parameter) 44 <12c> DW_AT_name : b 45 <12e> DW_AT_decl_file : 1 46 <12f> DW_AT_decl_line : 6 47 <130> DW_AT_type : <138> 48 <134> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24) 49 <1><138>: Abbrev Number: 4 (DW_TAG_pointer_type) 50 <139> DW_AT_byte_size : 8 51 <13a> DW_AT_type : <ac> 52 <1><13e>: Abbrev Number: 7 (DW_TAG_subprogram) 53 <13f> DW_AT_external : 1 54 <140> DW_AT_name : func1 55 <146> DW_AT_decl_file : 1 56 <147> DW_AT_decl_line : 13 57 <148> DW_AT_prototyped : 1 58 <149> DW_AT_type : <ac> 59 <14d> DW_AT_low_pc : 0x4005d0 60 <155> DW_AT_high_pc : 0x4005f9 61 <15d> DW_AT_frame_base : 0x4c (location list) 62 <161> DW_AT_sibling : <18a> 63 <2><165>: Abbrev Number: 6 (DW_TAG_formal_parameter) 64 <166> DW_AT_nam e : a 65 <168> DW_AT_decl_file : 1 66 <169> DW_AT_decl_line : 13 67 <16a> DW_AT_type : <ac> 68 <16e> DW_AT_location : 2 byte block: 91 5c (DW_OP_fbreg: -36) 69 <2><171>: Abbrev Number: 6 (DW_TAG_formal_parameter) 70 <172> DW_AT_name : b 71 <174> DW_AT_decl_file : 1 72 <175> DW_AT_decl_line : 13 73 <176> DW_AT_type : <138> 74 <17a> DW_AT_location : 2 byte block: 91 50 (DW_OP_fbreg: -48) 75 <2><17d>: Abbrev Number: 8 (DW_TAG_variable) 76 <17e> DW_AT_name : c 77 <180> DW_AT_decl_file : 1 78 <181> DW_AT_decl_line : 14 79 <182> DW_AT_type : <ac> 80 <186> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) 81 <1><18a>: Abbrev Number: 7 (DW_TAG_subprogram) 82 <18b> DW_AT_external : 1 83 <18c> DW_AT_name : main 84 <191> DW_AT_decl_file : 1 85 <192> DW_AT_decl_line : 23 86 <193> DW_AT_prototyped : 1 87 <194> DW_AT_type : <ac> 88 <198> DW_AT_low_pc : 0x400600 89 <1a0> DW_AT_high_pc : 0x400648 90 <1a8> DW_AT_frame_base : 0x98 (location list) 91 <1ac> DW_AT_sibling : <1e7> 92 <以降、けっこうはしょってます>
上で出した例、もちっと詳しくみてみますです。まず、データ格納構造から。で、説明のために、まず.debug_abbrevの例から以下の部分をひっこぬいてみました。
38 7 DW_TAG_subprogram [has children] 39 DW_AT_external DW_FORM_flag 40 DW_AT_name DW_FORM_string 41 DW_AT_decl_file DW_FORM_data1 42 DW_AT_decl_line DW_FORM_data1 43 DW_AT_prototyped DW_FORM_flag 44 DW_AT_type DW_FORM_ref4 45 DW_AT_low_pc DW_FORM_addr 46 DW_AT_high_pc DW_FORM_addr 47 DW_AT_frame_base DW_FORM_data4 48 DW_AT_sibling DW_FORM_ref4.debug_abbrev、すなわちデータ格納構造のデータは、上記の様な塊が、なんか羅列されてます。
7 DW_TAG_subprogram [has children]の様な感じですね。これにはちゃんと意味があって、以下となるです。
例の表記 | 名称 | ごせつめい |
"7" | Abbrev番号(Abbrev ID) | 「データ格納構造」毎に割り振られた、ユニークな数字です。ようするに、DWARF内での「データ格納構造」のお名前だと思ってください。 |
"DW_TAG_subprogram" | TAG名 | この「データ格納構造」が、何に関するデバッグ用の情報を格納するためのデータ構造か、の種類を特定するためのIDです。 このTAG名は、(そのうち作るよ)にあり一覧の数だけあります。 この例は、C言語ソース内の関数(subprogram)の情報を書くための「データ格納構造」だよってことを意味しています |
has children | 子データの存在有無 | この「データ格納構造」は、子扱いのデバッグ用データ構造を持つか、を示します。 例えば、関数のデータ構造(例)の場合、関数の引数は、この関数に関連する情報ですよね。なので、関数の引数のデバッグ情報は、関数のデバッグ情報の子ということになります。 これは、こう書いてもうーんなんで、下の.debug_infoでメモります |
次に、その下の行ですね。これは
DW_AT_external DW_FORM_flagです。これは、関数のデバッグ情報(DW_TAG_subprogram)が持つデバッグ情報の「属性」と「属性値の型」を示しています。
そして、続く行では、DW_AT_xxxxとDW_FORM_yyyyが続いていますね。これらの意味は、ざっと以下です。
38 7 DW_TAG_subprogram [has children] 39 DW_AT_external DW_FORM_flag 40 DW_AT_name DW_FORM_string # 関数名: 文字列で格納されている 41 DW_AT_decl_file DW_FORM_data1 # 関数が定義されたソースファイル名: .debug_line内のファイル名テーブルのIDを1Byte数値としてもつ 42 DW_AT_decl_line DW_FORM_data1 # 関数の開始行: .debug_line内でのソース行とプログラムコードアドレス関係表の開始位置を1Byte数値としてもつ 43 DW_AT_prototyped DW_FORM_flag # (恐らく)プロトタイプ宣言かどうか? : true/falseのフラグ形式で 44 DW_AT_type DW_FORM_ref4 # (恐らく)関数の戻り値の型?: DWARF内のオフセットを4Byteで? 45 DW_AT_low_pc DW_FORM_addr # プログラムコード上での関数開始アドレス: アドレス形式で(64bitなら8byte) 46 DW_AT_high_pc DW_FORM_addr # プログラムコード上での関数終了アドレス: アドレス形式で 47 DW_AT_frame_base DW_FORM_data4 # 関数のFrameBase : (まだ調査未だが)4Byteのデータ? 48 DW_AT_sibling DW_FORM_ref4 # このデータ構造の子ではに、次のデータ構造の.debug_info内での開始オフセット(.debug_infoの先頭から): 4byteのオフセット値上のコメントでは、まだDW_AT_xxxxx、DW_FORM_yyyyyを調べ切ってないので、恐らく、とか、未調査、とか書きましたが、TAG/AT/FORMはそれぞれ一覧で整理します(そのうち)
ということで、次に.debug_infoです。まず、以下の部分がイケニエです。
52 <1><13e>: Abbrev Number: 7 (DW_TAG_subprogram) 53 <13f> DW_AT_external : 1 54 <140> DW_AT_name : func1 55 <146> DW_AT_decl_file : 1 56 <147> DW_AT_decl_line : 13 57 <148> DW_AT_prototyped : 1 58 <149> DW_AT_type : <ac> 59 <14d> DW_AT_low_pc : 0x4005d0 60 <155> DW_AT_high_pc : 0x4005f9 61 <15d> DW_AT_frame_base : 0x4c (location list) 62 <161> DW_AT_sibling : <18a> 63 <2><165>: Abbrev Number: 6 (DW_TAG_formal_parameter) 64 <166> DW_AT_nam e : a 65 <168> DW_AT_decl_file : 1 66 <169> DW_AT_decl_line : 13 67 <16a> DW_AT_type : <ac> 68 <16e> DW_AT_location : 2 byte block: 91 5c (DW_OP_fbreg: -36)この.debug_infoでは、頭になんかヘッダっぽいものがありますが、とりあえず無視して、この部分を見て行きます。
<1><13e>: Abbrev Number: 7 (DW_TAG_subprogram)この行の意味ですが、以下です。
ここで、重要なのはただ1つで、DIEの冒頭でまずどの「データ格納構造」で記述されたデバッグ情報か、ということを、Abbrev IDを使って示している、ということです。
んで、この部分だけは全てのDIEで共通にしておくことで、関数やら変数やら型定義やら、どんなデバッグ情報の格納にも「DIE」を使って対応できるようにしている、ということです。
で、次2行目です。
53 <13f> DW_AT_external : 1で、これ、1行目のごせつめいで、Abbrev ID=7の構造にそって、このDIEの情報は格納されていることが分かってます。ので、Abbrev ID=7を見てやると
38 7 DW_TAG_subprogram [has children] 39 DW_AT_external DW_FORM_flag 40 DW_AT_name DW_FORM_string 41 DW_AT_decl_file DW_FORM_data1 42 DW_AT_decl_line DW_FORM_data1 43 DW_AT_prototyped DW_FORM_flag 44 DW_AT_type DW_FORM_ref4 45 DW_AT_low_pc DW_FORM_addr 46 DW_AT_high_pc DW_FORM_addr 47 DW_AT_frame_base DW_FORM_data4 48 DW_AT_sibling DW_FORM_ref4ですから、この2行目は
39 DW_AT_external DW_FORM_flagに該当することが分かります。よって、このデータの型はDW_FORM_flagであり、その値、つまり実際に.debug_infoに含まれている値は「1」ということになりますね。
54 <140> DW_AT_name : func1これも、Abbrev ID=7の3行目が、
40 DW_AT_name DW_FORM_stringになっていますから、.debug_infoに持っている値は「文字列」ということが分かり、その文字列は「func1」である、というふうにreadelf君が解析した、と言うことを示しています。
63 <2><165>: Abbrev Number: 6 (DW_TAG_formal_parameter) 64 <166> DW_AT_name : a 65 <168> DW_AT_decl_file : 1 66 <169> DW_AT_decl_line : 13 67 <16a> DW_AT_type : <ac> 68 <16e> DW_AT_location : 2 byte block: 91 5c (DW_OP_fbreg: -36)では、このDIEも1行づつ。。。といきたいところですが、これも、見てみると、前のDIEと構造自体は、おんなじですね。
32 6 DW_TAG_formal_parameter [no children] 33 DW_AT_name DW_FORM_string 34 DW_AT_decl_file DW_FORM_data1 35 DW_AT_decl_line DW_FORM_data1 36 DW_AT_type DW_FORM_ref4 37 DW_AT_location DW_FORM_block1なわけでして、これ.debug_info側と構造、とーぜん一致しています。ので、1行づつ見て行かなくても、大丈夫そうです。
63 <2><165>: Abbrev Number: 6 (DW_TAG_formal_parameter)の先頭です。"<2>"になっています=「子供DIE」です!
int func1( int a, int *b) {であります。 で、引数の1つめは。。。変数aですね!
69 <2><171>: Abbrev Number: 6 (DW_TAG_formal_parameter) 70 <172> DW_AT_name : b (中略) 75 <2><17d>: Abbrev Number: 8 (DW_TAG_variable) 76 <17e> DW_AT_name : cとなっていますので、きちんと表現されてるっぽいですね。
75 <2><17d>: Abbrev Number: 8 (DW_TAG_variable) 76 <17e> DW_AT_name : c 77 <180> DW_AT_decl_file : 1 78 <181> DW_AT_decl_line : 14 79 <182> DW_AT_type : <ac> 80 <186> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20) 81 <1><18a>: Abbrev Number: 7 (DW_TAG_subprogram) 82 <18b> DW_AT_external : 1 83 <18c> DW_AT_name : main80行目は、見ての通り子供DIEの行です。で、次の81行目は"<1>"になっていますんで、これは「関数の子供DIE」ではないことが分かります。(ちなみに、こいつはその下の83行目から、main関数ってわかります)
上記の.debug_infoのreadelf君解析結果では、Abbrev ID=0の情報は、分かりにくくなるのでカットしていますが、実際の.debug_infoのデータでは、上記の80行目と81行目の間に、Abbrev ID=0 (バイナリで0x00だけ)のDIEを持っていることになります。
なお、ここでいう81行目main関数のDIEも、CソースのDIEの「子供DIE」扱い(だから、"<1>"からはじまる)としていますので、1つのCソースのデバッグ情報終りにも、Abbrev ID=0だけのDIEが来ます。
注意したいのは、「.debug_abbrevには、その構造が子供DIEを持つか、の情報は含むものの、子供DIEであることを終え、1つ上の世代(レベル)のDIEであることを示す情報は.debug_infoにある」ということです。
ここまでで、DWARFなデバッグ情報のメイン所である、.debug_abbrev/.debug_infoセクションの大まかな構造、関連になるです。
んで、あとはというと、以下のことが分かれば、もうDWARFはほとんど読めたってことになりそう、ってことも分かって来ました。
おおざっぱにいって、これらの情報があれば、後は読んでいくだけ、と言う風になりそうです。ってことで、Dr.demon64に着手した際の最大難関と見られた、DWARF解析もようやっと見えて来ました、ということで、次からはこれを見て行きますです。
[PageInfo]
LastUpdate: 2013-06-12 22:14:10, ModifiedBy: koinec
[License]
FreeBSD Documentation License
[Permissions]
view:all, edit:members, delete/config:members