".debug_pubnames"セクションは、「グローバル関数(staticな宣言がされてない奴)」「グローバル変数」の名前から、.debug_info内でのそれらの情報が書いてある場所の位置(オフセット)を即刻引くための早見表みたいです。
".debug_pubtypes"セクションは、同様?に「グローバルな型」の名前から、.debug_info内でのそれらの情報が書いてある場所の位置(オフセット)を即刻引くための早見表みたいです。
(2013/5/14 まだちゃんと調べてないけど、恐らく「グローバルな型」=関数外部で宣言した、typedef xxxx ですねきっと。(C言語の場合)
ということで、構造みていきまーす!
えと、まず".debug_pubnamesセクション" と ".debug_pubtypesセクション" は、上記の通り、その目的は違うのですが、構造が「全く同じ」です。
よって、一緒に書いてますです。(これは、DWARF3な規格原文も一緒っす)
で、これらのセクションの中は、Compilation Unit、ようするに、.cソースの単位に、以下の構造でデータがつっこまれてます。
.cソースが複数あれば、この構造が、ソース数分連続する、って仕組みです。(あ、ただし、多分、.cソース内にグローバルxxxxがなければ、とーぜんないと思う)
構造ですが、これで終りらしいです。うむ、昨日の.debug_arangesと言い、このあたりは簡単ですね。(つか、frameとかlineが大変過ぎ。。。)
<ヘッダ>ですが、以下表の通りみたいです。 .debug_arangesによく似てますな。
No. | 項目名 | Size | 説明 |
1 | unit_length | 4Byte or 12byte 説明欄参照 | いつもながらの、データ長ですね。このunit_lengthを除いた、このレコード(<ヘッダ>から<0x00のオフセットまで>)の長さです。 ところで、サイズ欄の「説明欄参照」ですが、おもろい記述がありました この長さ、「unsigned扱いで、最初の4Byteをunsigned int扱いで読み出して、0xffffff00 以下ならそれがそのままサイズで、かつ32bit DWARFフォーマット。 逆に、4Byteの値が0xffffffff なら、 それは64Bit DWARFフォーマットで、続く8Byteにunsigned longで長さが格納される。」 これ、.debug_lineとか.debug_frameでヘッダのサイズが64bitコンパイルでなんで32bit って書いていましたが、どーやらこういう仕掛けで、64bitコンパイルでも32bit DWARFにしているみたいですね→gcc |
2 | version | 2Byte unsigned short | これもおなじみ君で、「このセクション」のバージョン番号です。 DWARD2とか3とかとは別のバージョンなんで、注意 |
3 | debug_info_offset | 4Byte(32bit DWARF) 8Byte(64bit DWARF)) どちらもunsigned整数 | このレコードで表現するグローバルxxxが居座っているCompilation Unit、すなわち.cソースのCompilation Unit Header(CUHeader)の位置(オフセット)です。 このオフセットは、.debug_infoの頭からのオフセットですね。 |
4 | debug_info_length | 4Byte(32bit DWARF) 8Byte(64bit DWARF)) どちらもunsigned整数 | .debug_infoセクション内での、No.3でリンクしているCU配下のデータの長さが入っている(よーです。ちょっと英訳自信なしこれ) |
<ヘッダ>に続いて、その<ヘッダ>が対象とするCU、.cソース内のグローバルxxxxの早見表になるデータが連続してつっこまれます。
早見表似奈留データですが、上の通り<オフセット>と<文字列>のセット、があるだけ連続するみたいです。で、それぞれの詳細は、以下ですね。
項目名 | データの表記方法 | 説明 |
<オフセット> | 4Byte (32bit DWARFの場合) 8byte (64bit DWARFの場合) | 続く<文字列>で表現される、グローバルxxxxの情報が書かれた.debug_info内でのオフセットみたいです。 なお、このオフセットは、<ヘッダ>:debug_info_offsetからのオフセット。 なので、.debug_infoセクションの先頭からのオフセット、にする場合は「<ヘッダ>:debug_info_offset + <オフセット>」の値になるっぽいです。 |
<文字列> | NULL文字を終端とする文字列 | そのままです。グローバルxxxxのソース中での名前文字列っぽいです。(Cの場合、C++は以下参照) 原文には「.debug_info内での"DW_AT_name"属性で示す名称」とありますが、C言語の場合なんかいじってるのかなぁ。。。 (関数名がちょっと怪しい。("_ アンダ_スコア"を関数名の頭に付けたものかもですね。) |
なお、CU内のグローバルxxxxがあるだけ、このセットを繰り返したあと、もうネタ切れー、となったら、<オフセット>=0 のデータ(DWARFのbit数次第で4Byteか8Byte表記)を付けて、それでそのCU分は終りです。
さらにcソースがある場合は、同じ構造を繰り返すっぽです。[[BR]
(わたくしC++はスーパーしろーとなんであんまり良く分からんですが。。。) 原文見る限り、注意数点あるっぽいです。
ということで、またもや実機でデータ見てみました。
まず、使ったソースです。今回は、ヘッダファイル含め3つのソースを用いました。
まず、1つめ。
/* .debug_aranges sample source - test1.c */ #include"test.h" int g1; extern int g2; // by test2.c extern int func1(int a, int b); // by test2.c int func2(int d) { return d + g2 + g1; } int main(int argc, char *argv[]) { int a, b, r; DATA d; // by test.h g1 = 1; g2 = 2; a = 3; b = 4; r = func1(a,b); d.integer = func2(r); d.str[0] = 't'; d.str[1] = 'e'; d.str[2] = 's'; d.str[3] = 't'; return r; }
んで、2発目
/* .debug_aranges sample source - test2.c */ int g2; int func1(int a, int b) { return a+b-g2; }
この2つは、.debug_arangesの時とほとんど、おんなじです。ただ、今回はpubtypesのデータを出したくて、以下のヘッダファイルを追加しました。
/* .debug_pubnames/pubtypes sample source - test.h */ typedef struct { int integer; char str[10]; } DATA;
ちなみに、使った環境は、以下です。
prompt # uname -a FreeBSD xxxx.koinec.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #0: amd64 prompt # gcc -v Using built-in specs. Target: amd64-undermydesk-freebsd Configured with: FreeBSD/amd64 system compiler Thread model: posix gcc version 4.2.1 20070831 patched [FreeBSD]
で、こいつらを"-g3"付きでコンパイルしたんですがね。。。。
ではありませんか!
ということで、.debug_pubnamesをいつも通り、セクション抜き出して、ダンプ→解析が以下の結果です。#ではじまる行はつっこんだコメントです。
# Hex. Dump by .debug_pubnames Section 00000000 28 00 00 00 : unit_length = 0x00000028 = 40 Byte # なので、32bit Dwarfフォーマットで、以下の長さは40Byteってことですね。 00000004 02 00 : version = 0x0002 = 2 # これは、そのままですね。ただ、毎度ですがこの2はDWARF2と言う意味ではないです。 00000006 00 00 00 00 : debug_info_offset = 0x00000000 # このヘッダ以下にある情報は、.debug_infoセクションの頭から0Byte目からのデータってことです。 0000000a 9b 01 00 00 : debug_info_length = 0x0000019b = 411 Byte # debug_info_offsetの場所から411Byteの範囲内に、以下に列挙するグローバル関数/変数の # 情報があるよってことです。 # それで、ヘッダが終り、ここから<オフセット><文字列>の繰り返しです。 0000000e c4 00 00 00 : <オフセット> = 0x000000c4 # なので、.debug_infoの先頭から、Header:debug_info_offset + <オフセット>の場所、 # すなわち、0x00000000 + 0x000000c4 = 0x000000c4 にある情報、ってことを示しています。 # では、その場所に何の情報があんの?が、次ですね。 00000012 66 75 6e 63 32 00 : <文字列>= func2 # です。なので、文字の通り、func2関数の情報が0x000000c4にあるってことが分かりました。 # これが正しいかは、最後に見てみますかね。 # で、func2は終り、次のレコードです。 00000018 f8 00 00 00 : <オフセット> = 0x000000f8 = 248Byte目 # .debug_infoの先頭から、0x00000000(debug_info_offset) + 0x000000f8 = 0x000000f8 # にある情報ですな。 0000001c 6d 61 69 6e 00 : <文字列> = main # ので、main関数ですね。 00000021 79 01 00 00 : <オフセット> = 0x00000179 = 377 Byte目 # まだ、0じゃないので、続きます。 00000025 67 31 00 : <文字列> = g1 # グローバル変数 g1 のでした。 00000028 00 00 00 00 : <オフセット> = 0x00000000 = 0 # というこで、オフセットが0になたので、これでこのCUは終りです。 # はてさて、まだ続いてますねデータ。→なので、次のCUです。 0000002c 1f 00 00 00 : unit_length = 0x0000001f 00000030 02 00 : version = 0x0002 00000032 9b 01 00 00 : debug_info_offset = 0x0000019b # これから、次2目のCUの開始位置は、0x0000019bであることが分かります。 # これ、下で本当か確かめます。 00000036 ca 00 00 00 : debug_info_length = 0x000000ca 0000003a 6d 00 00 00 : <offset> = 0x0000006d # 先頭からのオフセットは、0x00000208 0000003e 66 75 6e 63 31 00 : <文字列> = func1 00000044 b4 00 00 00 : <offset> = 0x000000b4 # 先頭からのオフセットは、0x0000024f 00000048 67 32 00 : <文字列> = g2 0000004b 00 00 00 00 : <offset> = 0x00000000 (終り)
よって、今回もarangesと同じく、あっさり終りました。ただ、本当に.debug_info側と一致しているかだけは、気になったんで、以下readelfコマンドで吐かせた.debug_infoと見比べてみます。
The section .debug_info contains: Compilation Unit @ offset 0x0: Length: 407 Version: 2 Abbrev Offset: 0 Pointer Size: 8 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit) <1><6d>: Abbrev Number: 2 (DW_TAG_structure_type) <2><75>: Abbrev Number: 3 (DW_TAG_member) <2><87>: Abbrev Number: 3 (DW_TAG_member) <1><96>: Abbrev Number: 4 (DW_TAG_base_type) <1><9d>: Abbrev Number: 5 (DW_TAG_array_type) <2><a6>: Abbrev Number: 6 (DW_TAG_subrange_type) <1><ad>: Abbrev Number: 7 (DW_TAG_base_type) <1><b0>: Abbrev Number: 4 (DW_TAG_base_type) <1><b8>: Abbrev Number: 8 (DW_TAG_typedef) <1><c4>: Abbrev Number: 9 (DW_TAG_subprogram) ←<>の2つ目が.debug_info内でのオフセットですが、ちゃんと0x000000c4になってますね。 <c6> DW_AT_name : func2 <2><eb>: Abbrev Number: 10 (DW_TAG_formal_parameter) <1><f8>: Abbrev Number: 9 (DW_TAG_subprogram) ←main関数もちゃんと0x000000f8になってますよ。 <fa> DW_AT_name : main <2><11e>: Abbrev Number: 10 (DW_TAG_formal_parameter) <2><12d>: Abbrev Number: 10 (DW_TAG_formal_parameter) <2><13c>: Abbrev Number: 11 (DW_TAG_variable) <2><148>: Abbrev Number: 11 (DW_TAG_variable) <2><154>: Abbrev Number: 11 (DW_TAG_variable) <2><160>: Abbrev Number: 11 (DW_TAG_variable) <1><16d>: Abbrev Number: 12 (DW_TAG_pointer_type) <1><173>: Abbrev Number: 12 (DW_TAG_pointer_type) <1><179>: Abbrev Number: 13 (DW_TAG_variable) ← はい。グローバル変数g1は0x00000179になってます。これもOK。 <17a> DW_AT_name : g1 <1><18e>: Abbrev Number: 14 (DW_TAG_variable) ← グローバル変数g2は、実体はtest2.cにあるので、pubnamesの指し先は、test2.c、すなわち下のCUです。 <18f> DW_AT_name : g2 # (参考) このグローバル変数g2がこっちにも出ているのは、恐らくexternして参照しているのを、出すようにしているからです。 Compilation Unit @ offset 0x19b: Length: 198 Version: 2 Abbrev Offset: 199 Pointer Size: 8 <0><1a6>: Abbrev Number: 1 (DW_TAG_compile_unit) <1><208>: Abbrev Number: 2 (DW_TAG_subprogram) ← これもOKですね。 <20a> DW_AT_name : func1 <2><22f>: Abbrev Number: 3 (DW_TAG_formal_parameter) <2><23b>: Abbrev Number: 3 (DW_TAG_formal_parameter) <1><248>: Abbrev Number: 4 (DW_TAG_base_type) <1><24f>: Abbrev Number: 5 (DW_TAG_variable) ← これもOK! <250> DW_AT_name : g2
ということで、.debug_pubnames/.debug_pubtypesもあっさり終了ですね。
.debug_pubtypesの現物を見れなかったのはちと悔しいのですが、まぁその内御目にかかるかと。
[PageInfo]
LastUpdate: 2013-05-28 22:14:35, ModifiedBy: koinec
[License]
FreeBSD Documentation License
[Permissions]
view:all, edit:members, delete/config:members