おしながき

ELFファイルフォーマット

  • .eh_frameセクションの構造と読み方

DWARFファイルフォーマット

NCURSESライブラリ

  • NCURSES Programing HOWTO ワタクシ的ほんやく
    1. Tools and Widget Libraries
    2. Just For Fun !!!
    3. References
  • その他、自分メモ
  • NCURSES雑多な自分メモ01


最近の更新 (Recent Changes)

2019-09-24
2013-10-10
2013-10-03
2013-10-01
2013-09-29
目次に戻る:DWARFファイルフォーマット

データ形式(DW_FORM_zzzz)一覧と意味、格納データの構造

DW_FORM_zzzzって何?

ということで、.debug_abbrevに登場した「TAGコード」「Attributeコード」「Formコード」の3兄弟ですが、まずは末っ子?の「Formコード」から見て行きます。
というのも、これが分からないと、.debug_infoの解析は、全くできなくなっちゃうからです。

で、DW_FORM_zzzzって何、という話ですが、これ簡単です。
先()に、.debug_infoと.debug_abbrevの関係を見ましたが、そこで.debug_infoで指定されたAbbrevレコード内には、格納されているデバッグ情報の種類として属性(Attributeコード)があり、その属性に対応する実際のデータの格納形式がこの値(Formコード)を表現されている、と例を示しましたが、そのコードです。
って、言葉で書くと全くワケが分からないので、()をおとなしく見てくださいです。


まず、DW_FORM_zzzzな一覧

ということで、考えるよりも先に、DW_FORM_zzzz的なFormコードの一覧を以下に列挙です。

番号 Form名 Class .debug_info内でのデータの持ち方(ごせつめい) .debug_info内
でのデータサイズ
(Byte単位)
1 DW_FORM_addr 0x01 address (デバッグ情報が格納されている実行ファイルの)アドレスサイズ分データが.debug_infoに直値として直接埋め込まれています。
この値は、再配置された後のメモリアドレス、です。
何のメモリアドレスかってことは、このFormコードを指定したAttributeコードによりけりです
なお、このアドレスサイズ、正確には.debug_infoのCUヘッダに書き込まれている値になります。
4Byte(32bit)
8Byte(64bit)
2 DW_FORM_block1 0x0a block こいつは、ある程度の長さを持った「バイト列=バイナリデータ」を.debug_infoに表現したい時に指定されます。
形式は、まずデータの最初の1Byte(unsigned char)に続くデータ列の長さ(0〜255)が格納されます。
んで、その次のバイトから、この長さの分、対象とするデータが直接.debug_infoに埋め込まれています。
この突っ込まれるデータは、本当のバイナリデータから、メモリアドレス、 他のDIEの参照オフセットとか、いろんなものが入るのですが、圧倒的に多いのが「DWARF expression」の数式です。
1Byte+(指定された長さ)
最大256Byte
3 DW_FORM_block2 0x03 block (No.2)DW_FORM_block1の最初の長さを2Byte(unsigned short)で表現するタイプです。
データの長さを2Byte(65535Byte)まで取れる以外はNo.2と全く同じです。
2Byte+(指定された長さ)
4 DW_FORM_block4 0x04 block (No.2)DW_FORM_block1の最初の長さを4Byte(unsigned int)で表現するタイプです。
データの長さを4Byte(約4GByte)まで取れる以外はNo.2と全く同じです。
(まぁ、実際4GByteを指定することはないけどねきっと)
4Byte+(指定された長さ)
5 DW_FORM_block 0x09 block こいつも、意味としては(No.2)と全く同じです。
が、最初のデータの長さを示す値が、1,2,4Byte固定値ではなく、uLEB128で表現されています。違いはそれだけです。
長さuLEB128のサイズ+(指定された長さ)
6 DW_FORM_data1 0x0b constant 1Byteのデータが.debug_infoに直値で埋め込まれています。それだけです。
あ、ただ、この値の解釈は、Attributeの意味に依存していて、符号付き整数、符号なし整数、DIEのオフセット、はたまた浮動小数点、だったりします。
(まぁ、1Byteのdata1の場合は、浮動小数点ってことはないけどねとーぜん、ただ、以下のdata2/4/8はあり得るです)
あと、Big/Little Endianの別は、ターゲットマシンに依存します。(つまり、x86/64ならとーぜんリトル、PowerPCならビッグ?です)
1Byte
7 DW_FORM_data2 0x05 constant (No.6)と意味は同じですが、見てのごとく、2Byteデータ(即値)です。 2Byte
8 DW_FORM_data4 0x06 constant
lineptr
loclistptr
macptr
rangelistptr
これも(No.6)と同じだけど、4Byteですね。
あ、あと、4Byte/8Byte版は、Classがいっぱいあります。これは後述
4Byte
9 DW_FORM_data8 0x07 constant
lineptr
loclistptr
macptr
rangelistptr
んで、いうまでもなく(No.6)の8Byte版ですね。 8Byte
10 DW_FORM_sdata 0x0d constant これも、data1/2/4/8と同じく「即値」です。
でも、1つだけ。。。これ、sLEB128形式の「即値」で埋め込まれています。よって、サイズの固定/制限はないっす。
あと、気づいてると思いますですが、signedです!
sLEB128
11 DW_FORM_udata 0x0f constant これは(No.10)と同じですが、uLEB128の「即値」です。符号は持っていない、正の整数、ですね。 uLEB128
12 DW_FORM_string 0x08 string こいつは、名前の通り「文字列」です。
んで、_stringな文字列は、.debug_info内(のDIE内)に、その文字列が直接埋め込まれている、文字列です。
なお、文字列の最後はNULL(0x00)です。
あと、.debug_infoのCompilation unit HeaderにDW_AT_use_UTF8なattributeがあるとき、この値は「UTF8」でエンコードされていますってことなんで、注意。
なお、このattribute君がいなかったら、文字コードは決められていません。(つか、ふつーに考えてASCIIだよね)
(NULL来るまでの長さ)
13 DW_FORM_strp 0x0e string こいつは、まずNo.12と同じく、「文字列」です。
ただし、格納場所が違っていて、こいつで指定された文字列は.debug_strセクション内にNULL文字終端で格納されています。
んじゃ、.debug_infoには何がはいっちょるの、ってことですが、これは「.debug_strの先頭から対象とする文字列までのバイト数=offset」が入ってます。
この点が違うっす。 ということで、こんな表の中に紛れてますが、.debug_strはただひたすらNULL終端の文字列がどばーっとつまってるだけ、ということも分かりましたです。
4Byte (32bit DWARF)
8Byte (64bit DWARF)
14 DW_FORM_flag 0x0c flag これは、一言でいうと「Boolean」ですね。(エイリアンじゃないです、念のため)
0なら、false。(つまり、そのattributeはないってことです)
逆に、0以外の値なら、trueです。
あ、表現自体は、1Byteの整数です。
1Byte
15 DW_FORM_ref_addr 0x10 reference これは、同じプログラム(実行ファイル)内の、他のCompilation UnitにあるDIEを指し示す時、に使いますです。(これよりも先に、まず下のNo.16見てからみてちょ)
特に、共有オブジェクト(.soなど)内のDIEを指し示す時に使われちゃいます。
で、値は対象とするDIEが含まれた実行ファイルや共有オブジェクトが持つ.debug_infoの先頭からのバイト数(オフセット)になりますです。
データの持ち方は、32bit DWARFなら4Byte, 64bit DWARFなら8byteの即値になるです。
4Byte (32bit DWARF)
8Byte (64bit DWARF)
16 DW_FORM_ref1 0x11 reference これは、同じCompilation Unit内(つまり、同じ.cなソース内)の他のDIE(Debbuging Information Entry)を参照する時に使われるです。
例えば、デバッグ情報内で、ある変数の型を指し示すとき、その型を定義しているデバッグ情報のDIEを指し示したいことがあったります。(ある変数のデバッグ情報内に、型のデバッグ情報まで持つのは冗長化して面倒ですよね)
こーいうときに、このFORMで、他のDIE(この例なら、変数の型)のDIEを指し示してやる、といった具合ですね。
じゃ、どうやって指し示すのかというと、「.debug_infoのCUヘッダ(Compilation Unitヘッダ)の先頭からのバイト数、すなわちオフセットで指し示しますです。
んで、このFORMが指定されちゃったときは、.debug_info内に1Byte符号無し整数が埋まってて、この値がオフセットになっちゃう、って具合です。
1Byte
17 DW_FORM_ref2 0x12 reference (No.16)の2Byte版です。つまり、オフセットがCUヘッダの先頭から255Byteに収まらないとき、使われるってことですね。 2Byte
18 DW_FORM_ref4 0x13 reference (No.16)の4Byte版です。以下同文 4Byte
19 DW_FORM_ref8 0x14 reference (No.16)の8Byte版ですね。こいつも、以下同文 8Byte
20 DW_FORM_ref_udata 0x15 reference これも、(No.16)と意味は同じです。
ただ、他のDIEへのオフセット値が、(No.16)などとは違って固定サイズではなく、「uLEB128」形式で.debug_infoに埋まっちゃってます。って違いがあります。
uLEB128
21 DW_FORM_indirect 0x16 (未定義:特殊) これは特殊用途で、こいつが指定された場合、対応する.debug_infoの場所にはuLEB128の数値が埋まっていて、この数値がDW_FORM_xxxになる、ということらしいです。
んで、原文には明確に書いてないけど、例えばこのuLEB128がDW_FORM_data4なら、このuLEB128の後ろに4Byteが続くってことでしょうかね。
なお、原文にはこいつを設けて、動的にFORMを決められるようにすることで、コンパイラ屋がいちいちAbbrevTableを追加しなくってもえーよーになるよね、ってあります。
(が、良く意味理解できてまへん。ま、例外なんでほっとくかとりあえず。(2013/8/12))
uLEB128 + 指定された長さ?


”Class”ってなに?

上の表の左から4番目の列に、怪しげな「Class」ってのがあります。んで、これ上では説明してないんですよね。んじゃ、これにゃに、って話です。
で、”Class”ですが、これずばり「DW_FORM_zzzzで指定されたデータの形式で、.debug_infoの中に埋まっているデータの解釈方法」のことです。

例を出すと、例えば、.debug_abbrevの中で、あるTAGがDW_AT_High_pcなAttributeを持っていて、この属性のデータの形式がDW_FORM_data8だったとします。
この時、後のページのDW_AT_yyyyの表に書き込みます(きっと)が、DW_AT_High_pcって属性は「このデバッグ情報エントリ(DIE)が対象とするオブジェクト(変数など)のメモリ上のアドレス範囲のうち、高位のもののアドレスを示す属性」の意味なんで、こいつがもつデータって、いうまでもなく「メモリアドレス」なわけです。
んで、そのメモリアドレスのデータ形式が"DW_FORM_data8"だから、このアドレスは8Byteの固定値(=64bit)ってな訳になるんですね。
次に、この例では、たまたま64bitだったんで、DW_FORM_data8な訳ですが、これもし32bitならどーしちゃいましょ、となると、やっぱりDW_FORM_data4がきちっと指定されちゃいます。

で、この例で気づいておきたいのは、これDW_AT_High_pcが来たら、そのデータが「メモリアドレス」を指すぞ、ってことは固定できる訳ですが、マシンやなどなど、な理由で、サイズや形式って固定できないことがあるってことです。
なので、DW_AT_yyyyのデータの解釈方法を予め「Class」として決めておき、そのデータの表現方法(DW_FORM_zzzz)は何が来てもいいようにしているわけです。
これで、DW_AT_High_pcのデータクラスが「address」ってことを知っていれば、その後ろのDW_FORM_zzzzでサイズが変わってもへっちゃらに解釈できるようになるのですね。
では、なぜ上の表(DW_FORM_zzzz)にClassがあるのか、というと、上の表のClassはその行のDW_FORM_zzzzがどのClassのデータ形式として指定される可能性があるのか、を逆引きとして書いてあるだけです。

ほんじゃ、ということで、Classの一覧表とその解釈方法を以下に。

Class名 解釈方法 取り得るDW_FORM_zzzz
address マシンのメモリアドレスとして解釈です DW_FORM_addr
block 長さ不定のバイナリデータの塊、として解釈してねって時のもんです。
主に、以下の例ありです。
* 再配置後or再配置可能な複数のアドレス
* 他のDIEへの参照
* その他適当なデータの塊
DW_FORM_block1/2/4
DW_FORM_block
constant 「定数」として解釈されます。
ただし、data1/2/4/8系は1/2/4/8バイトの定数、って意味で扱われる訳ですが、その定数の解釈の仕方はさまざまなんです。
「符号付き整数」「符号なし整数」「浮動小数点(4/8の場合)」などの固定値の場合がありますです。
(よーするに、必ず符号なし整数って訳じゃないです、ってこと。あくまでその長さの固定データ、ってことだけです)
DW_FORM_data1/2/4/8
DW_FORM_sdata
DW_FORM_udata
flag 単なるBooleanとして解釈せよってことです。
0=Flase、0以外=Trueってことです。
DW_FORM_flag
lineptr .debug_lineセクションの先頭から対象とするデータの場所までのオフセット値、って意味です。
.debug_info内のDIEから.debug_lineへリンクさせるときに指定されちゃいますね。
あと、再配置可能なオブジェクトファイル(つまり、.oなファイル)では再配置可能な、実行ファイルや.soな共有オブジェクトでは再配置後の値になるよ、
って原文に書いてますが、?????です。(なんで、lineセクションのオフセットが再配置??)
DW_FORM_data4/8
loclistptr .debug_locセクションの先頭から対象とするデータの場所までのオフセット値、です。
これも、.debug_infoから.debug_locをリンクするときに使われます。
こいつの原文にも、lineptrとおんなじ再配置の下りがあるけど、にゃにこれ??
DW_FORM_data4/8
macptr .debug_macinfoセクションの先頭から対象データまでのオフセット値です。
またこれも、.debug_infoから.debug_macinfoをリンクするとき用です。
やっぱり、再配置の下りがあるけど、ワカラナイ!
DW_FORM_data4/8
rangelistptr .debug_rangesセクションの先頭から対象のデータまでのオフセット値ですね
これも、.debug_infoからのリンク用です。
またしても、再配置の下りありですが、ワカラン!
DW_FORM_data4/8
reference これは、「他のDIEを参照先」として解釈です。参照先のDIEによって、2つのパターンがあるです。
(パターン1)同じCU(Compilation Unit)内の他のDIEを指す場合:.debug_infoの該当するCUヘッダの先頭バイトからのオフセット値として解釈です。
(パターン2) 同じプログラム内の、他のCU内にあるDIEを参照する場合:参照するDIEを含むオブジェクトファイルの.debug_infoの先頭バイトからのオフセット値。
なお、パターン2の場合は必ずDW_FORM_ref_addrが指定されます。それ以外はパターン1
DW_FORM_ref1/2/4/8
DW_FORM_ref_udata
DW_FORM_ref_addr
string 見ての通り、「文字列」として解釈です。
文字列は、必ずNULL文字(0x00)で終るルールっす。
あと、CUヘッダのエントリにDW_AT_use_UTF8が指定されてしまった場合は、これらの格納文字列はUTF8になります。
未指定の場合は、未定義です。(事実上、ASCII以外つかうなぁってことですねきっと)
DW_FORM_string
DW_FORM_strp


目次に戻る:DWARFファイルフォーマット