DWARFフォーマット内で、(デバッグ中の)値の計算方法やデバッグ対象の関数や変数のアドレスの表現方法です。
(雑談: 原文に "DWARF expressions describe how to compute a value or name a location"ってあって、nameは名前って名詞、って思い込んで訳そうとして、偉いくろーしました。これ、辞書ったら、nameにはなんと「指定する」なんて動詞用法もあるっぽいです。こんなん分かるか!)
といってても、まぁぼやっとしか分からんです。が、.debug_infoの解読には必ず突破要のもので、かつわからーんて言ってても何にもすすまんので、とにかくまずは読み進めて、メモっていきます。
ので、このページ、しばらく(相当?)な間、適当なメモなんで、読み飛ばしてくださいです。(2013/5/20)
とりあえず、Libgoblinへの実装は終わったので、ちょっとずづ内容ましにしていきます(2019/09/24)
でけたーって時が来たら、でけたよーって書きますです。
一般演算命令は、単純なスタックマシンに(値を)つっこむ動作(=push)する
スタックにpushするデータは、ターゲットマシンのアドレスサイズとする。
DWARF expressionの演算実行後のスタックの一番上の値は、オブジェクトのアドレス、配列の値、文字列などの結果になってる。
こいつらは、DWARFスタックに値をつっこむ役目みたいです。以下表に、整理
No. | 命令名称 | 命令Byte | 引数1 | 引数2 | せつめい |
1 | DW_OP_lit0 | 0x30 | - | - | 値 0 をDWARFスタックにつっこむ(push)みたいです。 |
2 | DW_OP_lit1 | 0x31 | - | - | 値 1 をDWARFスタックにつっこむ(push)みたいです。 |
: | ... | ... | - | - | (上記が2,3,4と続く。。。) |
32 | DW_OP_lit31 | 0x4f | - | - | 値 31 をDWARFスタックにつっこむ(push)みたいです。 |
33 | DW_OP_addr | 0x03 | アドレス ターゲットマシンのアドレスサイズ | - | 引数1で指定されたアドレス値をスタックにつっこむみたいです。 引数1のサイズは、動作マシンのアドレスサイズ、すなわち64bitなら8Byteですね。 |
34 | DW_OP_const1u | 0x08 | 1Byte unsigned char | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
35 | DW_OP_const1s | 0x09 | 1Byte signed char | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
36 | DW_OP_const2u | 0x0a | 2Byte unsigned short | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
37 | DW_OP_const2s | 0x0b | 2Byte signed short | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
38 | DW_OP_const4u | 0x0c | 4Byte unsigned int | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
39 | DW_OP_const4s | 0x0d | 4Byte signed int | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
40 | DW_OP_const8u | 0x0e | 8Byte unsigned long | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
41 | DW_OP_const8s | 0x0f | 8Byte unsigned long | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
42 | DW_OP_constu | 0x10 | uLEB128 | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
43 | DW_OP_consts | 0x11 | sLEB128 | - | 引数1をDWARFスタックにつっこむ(push)みたいです。 |
こやつらは、(指定された)レジスタに与えられた符号付きオフセットを足しこんだ結果(アドレス)をDWARFスタックにつっこむ命令みたいです。
No. | 命令名称 | 命令Byte | 引数1 | 引数2 | せつめい |
1 | DW_OP_fbreg | 0x91 | sLEB128 offset | - | 現在(実行中の)関数のDW_AT_frame_base属性値で表現されるアドレスに引数1のオフセットを足しこんだアドレスをスタックにつっこむ |
2 | DW_OP_breg0 | 0x70 | sLEB128 offset | - | reg0の値に引数1のオフセットを足しこんだアドレスをスタックにつっこむみたいです |
: | ... | ... | - | - | (上記が2,3,4と続く。。。) |
34 | DW_OP_breg31 | 0x8f | sLEB128 offset | - | reg31の値に引数1のオフセットを足しこんだアドレスをスタックにつっこむみたいです |
35 | DW_OP_bregx | 0x92 | uLEB128 Reg | sLEB128 offset | 引数1で指定されたregに引数2のオフセットを足しこんだアドレスをスタックにつっこむみたいです |
これらのもんは、DWARFスタックの操作をするもん。なお、スタックの一番のindexを0として説明。
No. | 命令名称 | 命令Byte | 引数1 | 引数2 | せつめい |
1 | DW_OP_dup | 0x12 | - | - | スタックの一番上の値を複製する。 とあるが、これ複製した値はいずこへ。。。(多分、スタックの一番上にpushだよきっと) |
2 | DW_OP_drop | 0x13 | - | - | スタックの一番上の値をpopします。つまり、一番上の値を取り出して、上から2番目の値を一番上にするのね。 |
3 | DW_OP_pick | 0x15 | 1Byte unsigned char stack index | - | 引数1で指定されたスタック番号のデータを、スタックの一番上にpushする。だから、pick(up)するって意味ね |
4 | DW_OP_over | 0x14 | - | - | スタックの上から2番目の値を、スタックの一番上にコピーする。 これは、No. DW_OP_pickで引数1に1を指定したときと同じふるまい |
5 | DW_OP_swap | 0x16 | - | - | スタックの一番上と、上から2番目を逆にする。だけ。 |
6 | DW_OP_rot | 0x17 | - | - | スタックの上から3つをグルグルしちゃう。つまり、一番上→3番目に、2番目→一番上に、3番目→2番目にする。 残念ながら、首位陥落する命令 |
7 | DW_OP_deref | 0x06 | - | - | これは、ちと複雑。スタックの一番上の値をまずpop(取り出す)→その値を「アドレス」とみなして→そのアドレスのメモリにある値を、スタックの一番上につむ、命令。 なお、みなしたアドレスから値をもって来る際のサイズは、実行しているマシンのアドレス幅でもってくる。よーは、64bitなら8byteもってきてしまう。 |
8 | DW_OP_deref_size | 0x94 | 1 Byte unsigned char data size | - | これは、No.7 DW_OP_derefと動きはほぼ、同じ。ただし、こっちは、スタックから取り出したアドレス、からちょっぱってくる値のサイズを引数1で指定された値にしちゃう、点が違う。 なお、ちょっぱってきたデータは、スタックに突っ込む前に、実行マシンのアドレスサイズ幅まで、0で拡張してしまう。。。 なお、引数1は、実行マシンのアドレスサイズを越えない、です。 |
9 | DW_OP_xderef | 0x18 | - | - | こいつは、No.7 DW_OP_derefの変種。まず、スタックの一番上の値を取り出して、アドレスとしてみなす。(これは、同じ) そして、上から2番目のスタック(命令開始時点での話、この段階ではイッコ取り出してるので、一番上)も取り出して、「アドレス空間指定子?」とみなす。 そして、この「アドレス空間指定子」と、元スタック一番上の、みなしたアドレス、の組合せから計算される、実際のアドレスにある値をちょっぱって、スタックの一番上につっこむ、命令っす。 さて、「アドレス空間指定子」ってのが、怪しすぎますがね。。。たぶん、これ、「セグメントアドレス」的なもんだと思います。(もしくは、スーパーファミコンなどでいう「バンク指定」みたいな感じ?) なお、「アドレス空間指定子」とみなしたアドレスから、実際のアドレスを計算する方法は、「実装で定義された計算方法」って書いてあって、特定してません。マシン依存だと。 |
10 | DW_OP_xderef_size | 0x95 | 1 Byte unsigned char data size | - | これは、No.9のDW_OP_xderefと同じふるまい。 ただし、計算されたアドレスから値引っ張って来る時のサイズは、引数1で指定されます。この指定の考え方は、No.8と同じです |
11 | DW_OP_push_object_address | 0x97 | - | - | (これ、英語よくワカリマセン。。。。) ユーザが(デバッガ上で与えた)評価式内のオブジェクトのアドレスをスタックに突っ込む。 この「オブジェクト」は、この命令が使われたDIE(Debug Information Entry)か、ユーザ指定の評価式を評価する前段階で動的に(アドレスが)決定される配列/構造体/クラスによって表現される、独立した変数なのであーる。(←規約書、マニュアルの類の英文としては、長すぎじゃー) なお、こいつはDWARF3新参組選手 あ、あと斜体文字の注釈がこれ原文にありますが、ナニカイテイルカ、ワタシワカリマセーン!(つか、この規約書の全体的な英語レベルから見て、このブロックだけ難解過ぎ→DWARF3新参なんで、そのうちに。) |
12 | DW_OP_form_tls_address | 0x9b | - | - | こいつは、スタック(の一番上)から値をpopして → 現在のスレッドのTLS(Thread-Local Storage)のアドレスに変換して → 変換したアドレスをスタックにつっこむ、命令。 もし、子スレッドじゃなくって、メインのスレッド(もしくは、丸値スレッドにしてない)場合は、メインのスレッドに所属するもの、として処理。 また、もし共有ライブラリのDWARF情報内にこいつがいた場合は、共有ライブラリのTLSのアドレスに変換する。 <注釈>これ、英訳もそのまんま、ですし、書くのも簡単ですが。。。実装どーすんだろ、これ。どうやって変換するんだろ。。。(そーとー大変なよーなー) あ、これもDWARF3新参 |
13 | DW_OP_call_frame_cfa | 0x9c | - | - | Call Frame Information(.debug_frameセクション)から得られるCall Frame Address(CFA)をスタックにpushする命令 これも、DWARF3新参組っす |
にしても、いやぁ最後3つの英語はスーパー難解でごわす。(ワタクシには。。。)
これらは、タイトルの字のごとく、です。
No. | 命令名称 | 命令Byte | 引数1 | 引数2 | せつめい |
1 | DW_OP_abs | 0x19 | - | - | スタックの一番上の値をpop(取り出)して、符号月数と解釈してその絶対値をpushしちゃいます。 もし、絶対値を表現することができなければ、結果は「未定義」です。って、絶対が表現できないってどーいうケースを指しているんだろ? |
2 | DW_OP_and | 0x1a | - | - | 上から2つのスタックをpopして、それらの値を"and"なbit演算をして、結果をスタックにつっこむ、です |
3 | DW_OP_div | 0x1b | - | - | 上から2つのスタックをpopして、上から2番目の値を一番上の値で、符号付きで割算して、結果をスタックにpush |
4 | DW_OP_minus | 0x1c | - | - | 上から2つのスタックをpopして、上から2番目だった値から、一番上の値を引き、結果をスタックにpush |
5 | DW_OP_mod | 0x1d | - | - | 上から2つのスタックをpopして、上から2番目だった値を一番上の値で割った「余り」を結果として、スタックにpush |
6 | DW_OP_mul | 0x1e | - | - | 上から2つのスタックをpopして、2つのスタック値をかけ算して、結果をスタックにpush |
7 | DW_OP_neg | 0x1f | - | - | 一番上のスタック値をpopって、符号を逆にし、またスタックへpush。(マイナスなら、プラスにしちゃう) |
8 | DW_OP_not | 0x20 | - | - | 一番上のスタック値をpop→ビット反転して→またまたスタックへぷーっしゅ! |
9 | DW_OP_or | 0x21 | - | - | 上から2つのスタックをpopして、or演算してすたっくへぷっしゅです |
10 | DW_OP_plus | 0x22 | - | - | 上から2つのスタックをpopして、お互いを足して、結果をスタックへpush |
11 | DW_OP_plus_uconst | 0x23 | uLEB128 | - | 一番上のスタックをpopして、引数1の値を足して、結果をスタックへpush こいつは、"DW_OP_limX DW_OP_plus"の組で表せられないケースに使うっぽい |
12 | DW_OP_shl | 0x24 | - | - | 上から2つのスタック値をpopって、元2番目のスタック値を元一番上のスタック値のビット数分、左シフトです。で、結果はいつもどおりスタックへまたプッシュ |
13 | DW_OP_shr | 0x25 | - | - | 上から2つスタック値をpopして、元2番目スタック値を元一番上スタック値のビット数分、右シフトします。 このとき、左側は0で埋めて行きます。すなわち、符号は保存されません。 |
14 | DW_OP_shra | 0x26 | - | - | 上から2つのスタック値をpopして、元番目スタック値を元一番上スタック値のビット数分、右シフトします。 なお、こっちは、2よりでっかい数値で割る、すなわち1ビットでも右シフトするとき、元2番目スタック値の一番左のビットの値で左を埋めて行きます。 よーは、符号が保存されます。(だから、shraの最後のaはarithmetically、数学的、いかにも?) |
15 | DW_OP_xor | 0x27 | - | - | 上から2つのスタック値をpopして、互いのxorを結果としてスタックにpush |
って、オーバー?なタイトルになってます(原文も)が、よーはif文とかジャンプとかです。
No. | 命令名称 | 命令Byte | 引数1 | 引数2 | せつめい |
1 | DW_OP_eq | 0x29 | - | - | まず、上から2つスタックからpop。で、以下の比較をやって、真なら1をスタックpush。偽なら0をスタックpush <元2番目スタック値> = <元一番上スタック値> なお、元2番目、一番上スタック値は共に符号付き扱いで判定 |
2 | DW_OP_ge | 0x2a | - | - | まず、上から2つスタックからpop。で、以下の比較をやって、真なら1をスタックpush。偽なら0をスタックpush <元2番目スタック値> ≧ <元一番上スタック値> なお、元2番目、一番上スタック値は共に符号付き扱いで判定 |
3 | DW_OP_gt | 0x2b | - | - | まず、上から2つスタックからpop。で、以下の比較をやって、真なら1をスタックpush。偽なら0をスタックpush <元2番目スタック値> > <元一番上スタック値> なお、元2番目、一番上スタック値は共に符号付き扱いで判定 |
4 | DW_OP_le | 0x2c | - | - | まず、上から2つスタックからpop。で、以下の比較をやって、真なら1をスタックpush。偽なら0をスタックpush <元2番目スタック値> ≦ <元一番上スタック値> なお、元2番目、一番上スタック値は共に符号付き扱いで判定 |
5 | DW_OP_lt | 0x2d | - | - | まず、上から2つスタックからpop。で、以下の比較をやって、真なら1をスタックpush。偽なら0をスタックpush <元2番目スタック値> < <元一番上スタック値> なお、元2番目、一番上スタック値は共に符号付き扱いで判定 |
6 | DW_OP_ne | 0x2e | - | - | まず、上から2つスタックからpop。で、以下の比較をやって、真なら1をスタックpush。偽なら0をスタックpush <元2番目スタック値> != <元一番上スタック値> なお、元2番目、一番上スタック値は共に符号付き扱いで判定 |
7 | DW_OP_skip | 0x2f | 2 Byte signed short | - | DWARF expression 内での強制ジャンプ命令(よーするに、goto) 現在の命令(DW_OP_skip)から、引数2の値の分、前か後ろにジャンプ。 (ちょっとホンヤク自身なし→)前に行く場合は現在の命令の箇所から、後ろにジャンプの場合は、引数2の後ろ、すなわち2バイト後ろからカウントする(らしい) |
8 | DW_OP_bra | 0x28 | 2 Byte signed short | - | 条件判定後の結果を加味したジャンプ命令。 まず、一番上のスタックをpopして、もしpopした値が0じゃなかったら、DW_OP_skipと同様の方法でジャンプする。 popった値が0(偽)なら、なーんにもせんで命令終り |
9 | DW_OP_call2 | 0x98 | 2 Byte unsigned short offset of DIE | - | (これ、英語ムズカシすぎて、ワカリマッセーン!以下、とりあえずバカな直訳) この命令は、DWARFexpressionの(式の)評価の制御を、参照されたDIE内のDW_AT_location属性値が指し示すところへ移動させます。 もし参照先DIEにDW_AT_locationがなかったら、意味をなさない。 DW_AT_location内でのDWARF expressionの実行はスタックの値をふやしたり、へらしたりする。 (DW_AT_location属性値先を)呼び出した時のスタックの値は、呼び出したDWARF expressionへの引数となり、呼び出された表現によって残されたスタックの値は、呼び出す側/呼び出された側の事前の合意によって、戻り値として扱われる。 なんか、よーは「関数」のcallであり、DW_AT_locationに呼び出される関数がある、と読めます。ただ、まだDW_AT_locationが未調査なので、これはそこ判明したから補足ですね。 あと、引数2は2Byteの、現在の.debug_info内のCUの先頭からのoffsetで、このoffset先には、演算子を含んでいない実行可能な共有オブジェクトを含んでいるDIE ちなみに、DWARF3新参選手 |
10 | DW_OP_call4 | 0x99 | 4 Byte unsgined int offset of DIE | - | No.9 DW_OP_call2の引数4byte版。あとは全部No.9とおんなじ。 |
11 | DW_OP_call_ref | 0x9a | 4 or 8 Byte unsigned offset of DIE | - | 基本は、No.9のDW_OP_call2と同じ。相違点は以下 引数1は、32bit DWARFなら4byte、64bit DWARFなら8byteのoffset このオフセットは、.debug_infoセクションの先頭からのオフセット(これが、上2つとは違う) |
表にも書きましたが、No.9/10/11は、DW_AT_locationを要調査ですね。
No. | 命令名称 | 命令Byte | 引数1 | 引数2 | せつめい |
1 | DW_OP_nop | 0x96 | - | - | 読んで字のごとく、なんにも、しません。なまけます。。。じゃなくって、パディング用です。 無視でOK |
[PageInfo]
LastUpdate: 2019-09-24 12:46:34, ModifiedBy: koinec
[License]
FreeBSD Documentation License
[Permissions]
view:all, edit:members, delete/config:members