[インデックス 17845] ファイルの概要
このコミットは、Go言語のデバッグ情報パーサーであるdebug/dwarf
パッケージに、DWARF 4形式の新しい定数を追加し、それらのパースに対応するための変更を加えています。これにより、Clangコンパイラが生成するDWARF 4形式のデバッグ情報を正しく処理できるようになります。
コミット
- コミットハッシュ:
7dbbb53f3743aa1a654d75dd43ed4affc3ddc23d
- Author: Russ Cox rsc@golang.org
- Date: Tue Oct 29 10:36:51 2013 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7dbbb53f3743aa1a654d75dd43ed4affc3ddc23d
元コミット内容
debug/dwarf: add DWARF 4 form constants
Some versions of clang generate DWARF 4-format attributes
even when using -gdwarf-2. We don't care much about the
values, but we do need to be able to parse past them.
This fixes a bug in Go 1.2 rc2 reported via private mail using
a near-tip version of clang.
R=golang-dev, iant, dvyukov
CC=golang-dev
https://golang.org/cl/18460043
変更の背景
この変更の背景には、Go 1.2リリース候補2(rc2)におけるデバッグ情報のパースに関するバグがありました。具体的には、一部のバージョンのClangコンパイラが、-gdwarf-2
オプション(DWARFバージョン2形式のデバッグ情報を生成するよう指示するオプション)を使用しているにもかかわらず、内部的にDWARF 4形式の属性を生成してしまうという問題がありました。
Goのdebug/dwarf
パッケージは、実行可能ファイルに埋め込まれたDWARFデバッグ情報を解析するために使用されます。このパッケージがDWARF 4形式の新しい属性を認識できない場合、パースエラーが発生し、デバッグ情報が正しく読み取れないという問題が生じます。
このコミットは、Clangが生成するこれらのDWARF 4形式の属性をGoのデバッガが「パースしてスキップする」ことができるようにすることを目的としています。つまり、これらの属性の具体的な値に深い関心があるわけではなく、それらを正しく読み飛ばして、残りのデバッグ情報のパースを続行できるようにすることが重要でした。この修正は、プライベートメールで報告された、Clangの最新に近いバージョンを使用したバグ報告に対応するものです。
前提知識の解説
DWARFとは
DWARF (Debugging With Arbitrary Record Formats) は、プログラムのソースコードとコンパイルされたバイナリコードとの間のマッピングを記述するための標準的なデバッグ情報形式です。コンパイラによって生成され、実行可能ファイルや共有ライブラリに埋め込まれます。デバッガはDWARF情報を使用して、ソースコードレベルでのデバッグ(変数名の解決、行番号へのマッピング、スタックトレースの表示など)を可能にします。
DWARFは、以下のような情報を含みます。
- コンパイル単位 (Compilation Unit): ソースファイルごとの情報。
- 型情報 (Type Information): 変数や関数のデータ型。
- 変数情報 (Variable Information): 変数の名前、型、メモリ上の位置。
- 関数情報 (Function Information): 関数の名前、引数、戻り値、コードの範囲。
- 行番号情報 (Line Number Information): バイナリコードのアドレスとソースコードの行番号のマッピング。
- ロケーション情報 (Location Information): 変数がレジスタやメモリのどこに存在するかを示す式。
DWARFのバージョン
DWARFには複数のバージョンがあり、それぞれ新しい機能や改善が導入されています。このコミットで言及されているのは、DWARF 2とDWARF 4です。
- DWARF 2: 広く使用されているバージョンで、多くのシステムでサポートされています。
- DWARF 4: DWARF 3の後継として登場し、いくつかの新しい属性、フォーム、オペコードが導入されました。特に、型シグネチャ(Type Signature)やセクションオフセット(Section Offset)の扱いが改善されています。
DWARFの「フォーム (Form)」
DWARFでは、デバッグ情報の属性(例えば、変数の値、型、ロケーションなど)がどのようにエンコードされるかを「フォーム」で定義します。フォームは、属性のデータの種類(整数、文字列、参照、オフセットなど)とサイズを示します。
このコミットで追加された主要なDWARF 4のフォーム定数は以下の通りです。
DW_FORM_sec_offset
:- DWARF 4で導入されました。
- ELFセクションや実行可能ファイルまたはライブラリの他のサブコンポーネントへのオフセットを表すために使用されます。
- 32ビットDWARFでは4バイト、64ビットDWARFでは8バイトのサイズを持ちます。
- DWARF 2および3では、この目的のために
DW_FORM_data4
またはDW_FORM_data8
が使用されていました。 - 主に、
DW_AT_stmt_list
(行番号テーブルへのオフセット)、DW_AT_loclist
(ロケーションリストへのオフセット)、DW_AT_macinfo
(マクロ情報へのオフセット)、DW_AT_rangelist
(アドレス範囲リストへのオフセット) などの属性で使用されます。
DW_FORM_exprloc
:- DWARF 4で導入されました。
- DWARF式(DWARF Expression)を示すために使用されます。DWARF式は、値に評価されるか、またはロケーションを記述します。
- このフォームのデータは、符号なしLEB128形式の長さ(式のバイト数)に続き、その指定された長さのバイトシーケンス(式自体)で構成されます。
DW_FORM_ref_sig8
:- DWARF 4で導入されました。
- 型シグネチャ(Type Signature)を参照するために使用される参照型です。
- 特に、分割DWARFオブジェクト(Split DWARF)のようなシナリオで重要になります。これは、参照される型の定義が別のオブジェクトファイルに存在する可能性がある場合に利用されます。
技術的詳細
このコミットは、Goのdebug/dwarf
パッケージがDWARF 4形式の新しいフォーム定数を認識し、それらを適切にパースできるようにするためのものです。
debug/dwarf
パッケージは、DWARF情報を読み取る際に、各属性のフォームに基づいてデータを解釈します。新しいフォームが導入された場合、そのフォームに対応する読み取りロジックを追加する必要があります。
具体的には、以下の点が技術的な詳細として挙げられます。
- 新しいフォーム定数の定義:
src/pkg/debug/dwarf/const.go
に、formSecOffset
、formExprloc
、formFlagPresent
、formRefSig8
といったDWARF 4の新しいフォーム定数が追加されました。これらは、DWARF仕様で定義されている対応するDW_FORM_
定数の内部表現です。 entry.go
でのパースロジックの拡張:src/pkg/debug/dwarf/entry.go
内のbuf.entry
メソッドは、DWARFエントリの属性を読み取る主要なロジックを含んでいます。このメソッド内のswitch
文が拡張され、新しいフォーム定数に対応するケースが追加されました。formSecOffset
の処理: このフォームはセクションオフセットを表すため、DWARFのビット幅(32ビットか64ビットか)に応じて、uint32()
またはuint64()
を呼び出してオフセット値を読み取ります。dwarf64()
メソッドで現在のDWARFのビット幅を確認し、それに基づいて適切なサイズの整数を読み込むロジックが実装されています。formExprloc
の処理: このフォームはDWARF式を表すため、まずLEB128形式で式の長さを読み取り(b.uint()
)、その長さに基づいてバイト列を読み取ります(b.bytes(int(b.uint()))
)。formRefSig8
の処理: このフォームは64ビットの型シグネチャ参照を表すため、b.uint64()
を呼び出して64ビットの符号なし整数を読み取ります。
- 既存の
formFlagPresent
のコメント追加:formFlagPresent
はDWARF 4で導入されたフォームですが、このコミット以前から存在していました。今回のコミットで「New in DWARF 4.」というコメントが追加され、その由来が明確化されました。 - Clangとの互換性: コミットメッセージにあるように、Clangが
-gdwarf-2
を指定してもDWARF 4形式の属性を生成するケースがあるため、Goのデバッガがこれらの新しいフォームを認識し、パースできることが重要でした。これにより、GoのツールチェーンがClangでコンパイルされたバイナリのデバッグ情報をより堅牢に扱えるようになります。
この変更は、Goのデバッガが最新のコンパイラツールチェーン(特にClang)によって生成される多様なDWARF形式に対応し、デバッグ情報の互換性と堅牢性を向上させる上で不可欠なものです。
コアとなるコードの変更箇所
src/pkg/debug/dwarf/const.go
--- a/src/pkg/debug/dwarf/const.go
+++ b/src/pkg/debug/dwarf/const.go
@@ -207,7 +207,10 @@ const (
formRef8 format = 0x14
formRefUdata format = 0x15
formIndirect format = 0x16
+ formSecOffset format = 0x17
+ formExprloc format = 0x18
formFlagPresent format = 0x19
+ formRefSig8 format = 0x20
)
// A Tag is the classification (the type) of an Entry.
src/pkg/debug/dwarf/entry.go
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/debug/dwarf/entry.go
@@ -188,6 +188,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// flag
case formFlag:
val = b.uint8() == 1
+ // New in DWARF 4.
case formFlagPresent:
// The attribute is implicitly indicated as present, and no value is
// encoded in the debugging information entry itself.
@@ -236,6 +237,30 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
b.err = b1.err
return nil
}
+
+ // lineptr, loclistptr, macptr, rangelistptr
+ // New in DWARF 4, but clang can generate them with -gdwarf-2.
+ // Section reference, replacing use of formData4 and formData8.
+ case formSecOffset:
+ is64, known := b.format.dwarf64()
+ if !known {
+ b.error("unknown size for DW_FORM_sec_offset")
+ } else if is64 {
+ val = int64(b.uint64())
+ } else {
+ val = int64(b.uint32())
+ }
+
+ // exprloc
+ // New in DWARF 4.
+ case formExprloc:
+ val = b.bytes(int(b.uint()))
+
+ // reference
+ // New in DWARF 4.
+ case formRefSig8:
+ // 64-bit type signature.
+ val = b.uint64()
}
e.Field[i].Val = val
}
コアとなるコードの解説
src/pkg/debug/dwarf/const.go
の変更
このファイルでは、DWARFのフォーム定数がGoのformat
型として定義されています。追加された行は、DWARF 4で導入された新しいフォームに対応する定数を定義しています。
formSecOffset = 0x17
:DW_FORM_sec_offset
に対応。formExprloc = 0x18
:DW_FORM_exprloc
に対応。formRefSig8 = 0x20
:DW_FORM_ref_sig8
に対応。
これらの定数は、debug/dwarf
パッケージがDWARF情報をパースする際に、どのフォームのデータを読み取るべきかを識別するために使用されます。
src/pkg/debug/dwarf/entry.go
の変更
このファイルは、DWARFエントリ(デバッグ情報の論理的な塊)をパースするロジックを含んでいます。func (b *buf) entry(...)
メソッドは、DWARFエントリ内の各属性を読み取る際に、その属性のフォームに基づいて適切な読み取り関数を呼び出します。
変更点では、switch
文に新しいcase
が追加され、それぞれの新しいDWARF 4フォームに対応するデータ読み取りロジックが実装されています。
case formFlagPresent:
: 既存のformFlagPresent
のケースに「New in DWARF 4.」というコメントが追加されました。これは、このフォームがDWARF 4で導入されたものであることを明示しています。case formSecOffset:
:- このケースは、
DW_FORM_sec_offset
を処理します。 b.format.dwarf64()
を呼び出して、現在のDWARFのフォーマットが64ビットであるかどうかを判断します。これは、セクションオフセットのサイズがDWARFのビット幅に依存するためです。- もし
dwarf64()
がtrue
を返せば64ビットオフセットとしてb.uint64()
を読み込み、そうでなければ32ビットオフセットとしてb.uint32()
を読み込みます。 !known
の場合(DWARFのビット幅が不明な場合)はエラーを報告します。- コメントで「New in DWARF 4, but clang can generate them with -gdwarf-2.」とあり、Clangの挙動に対応していることが強調されています。
- このケースは、
case formExprloc:
:- このケースは、
DW_FORM_exprloc
を処理します。 b.uint()
を呼び出して、DWARF式の長さをLEB128形式で読み取ります。- その長さを
int
にキャストし、b.bytes()
を呼び出して、その長さ分のバイト列(DWARF式自体)を読み取ります。 - 「New in DWARF 4.」とコメントされています。
- このケースは、
case formRefSig8:
:- このケースは、
DW_FORM_ref_sig8
を処理します。 b.uint64()
を呼び出して、64ビットの型シグネチャを読み取ります。- 「New in DWARF 4.」とコメントされています。
- このケースは、
これらの変更により、Goのdebug/dwarf
パッケージは、DWARF 4形式のデバッグ情報に含まれるこれらの新しいフォームを正しく解釈し、パースエラーを回避できるようになりました。これにより、Goのデバッグツールがより広範なコンパイラとデバッグ情報形式に対応できるようになり、Go開発者のデバッグ体験が向上します。
関連リンク
- Go CL 18460043: https://golang.org/cl/18460043
参考にした情報源リンク
- DWARF Standard (dwarfstd.org):
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGFzfyAK43IRYmYUhdXewsWw8X3XIqEsXGMSdpm7mJFDLmbE3gJFWTBWGWQpW12ITLY_IXjSjQtqQkVzFfZcTxj61toaTOqwQ-JPJn4SGlqrwndsKHOa9rNVRtp-2h3xtELvMN8vpfTaI8B (DW_FORM_sec_offset)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH3YqDkhDpdI7rRWTeDq2mNDi1BGw0O1e998SHx4mfOZ_rs92Axybe3mEF91qNgvJB1zIeyrRFYqsuVQPND8t2wzj6HOAgpIdqOJFVY0kY_InKJQNEla-uuOOWqz_6i7dI-qJPB (DW_FORM_exprloc)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEsA5o5Wg3eSj13nUEn5Cw_75S2keDr7OnEtKJhou8ZKmWYitt7HbXFMcVaBrwdppn1xa-JbmKVSUaInYy-dtp5wKVmvP24OL4Gl4QFTlOHKSVs8NZtC7u6R3S4T-h3 (DW_FORM_ref_sig8)
- LLVM.org: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFQV5PkTCLoA4jR2qQ_Z1PG62R5G5PJuSLY-E4J7YBn1-jj7-xCEUPWIHwHF1485a3ljDW-pg_hl-Jb9NIC8CynhAgRK9JhBmNZJgVb0NmQfg2n3LCZtz0wdg== (DW_FORM_sec_offset)
- Calabro.io: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG_PYMUhKUhpxbLzpVS4G4WxPV3mutWHxlAxyJNLaZXvBtrWoGTlorm56j5auv-Y8rENDk1HmLneB-WP1CZmMA_pCXY8-x9lWVO1hNb9sojg3C3_OGqbdw= (DW_FORM_exprloc, DW_FORM_ref_sig8)
- Daemon-systems.org: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGrYPI6BFdni6H6j-i4lOF351kPI45-Cvy1QcZwRuIZQvAn8RKX1XoxoDM1IO0F3MJYin2wGw9nJ4v2uykCHSVBjHLbhTbwQKO3ZypHerEniONoUZ_7ZgF0n_KH3Vvjv16a-W359gfxPEwnE4NW9mpm79TeA4T (DW_FORM_exprloc)
- Sourceware.org: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH5hgFWDo-ZQiWOQZjk-VE4ctTX51m4Ek5dxXVakjUXLbBd0CQ7WMsSA8Exh8OHrtCXhiqG_DkRzc6Bzvctv6UyyZMxOeCbA9lt7ghvUsiQUN_jdFTI6XUHphF21MUx08jsyEqrywHOfuTjpdtBI1i5KY8aa9rGF8J_UP7dTUx-2IshXNB62ztIqNB05zcnP2R8t556ZKIIWlRBEMhUnxB8oLK97Q== (DW_FORM_ref_sig8)