[インデックス 15840] ファイルの概要
コミット
commit b79afe1b714e225a2b79f639e0956716de34ca64
Author: Ian Lance Taylor <iant@golang.org>
Date: Tue Mar 19 13:59:37 2013 -0700
debug/dwarf: support for DWARF 3
R=rsc
CC=golang-dev
https://golang.org/cl/7662045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b79afe1b714e225a2b79f639e0956716de34ca64
元コミット内容
debug/dwarf
: DWARF 3 のサポート
変更の背景
このコミットは、Go言語のデバッグ情報フォーマットであるDWARFのサポートをDWARFバージョン3に拡張することを目的としています。DWARFは、コンパイラやリンカによって生成される実行可能ファイルに埋め込まれるデバッグ情報のための標準フォーマットです。デバッガは、この情報を使用して、ソースコードレベルでのステップ実行、変数検査、スタックトレースの表示などを行います。
DWARFのバージョンが上がるにつれて、新しい機能や最適化が導入され、より効率的で表現力豊かなデバッグ情報を提供できるようになります。この変更は、Goのツールチェインがより新しいDWARFバージョンを理解し、それを利用できるようにすることで、デバッグ体験の向上や、より新しいコンパイラやリンカとの互換性を確保するために行われました。特に、DWARF 3では、64ビットのアドレスサイズや、より柔軟な参照形式のサポートが強化されており、これに対応することで、より大規模なプログラムや異なるアーキテクチャでのデバッグが改善されます。
前提知識の解説
DWARF (Debugging With Attributed Record Formats)
DWARFは、プログラムのデバッグ情報を表現するための標準的なフォーマットです。コンパイルされたバイナリファイルに埋め込まれ、デバッガがソースコードレベルでプログラムの実行を理解し、制御するために必要な情報(変数名、型情報、関数、行番号とアドレスのマッピングなど)を提供します。
DWARFのバージョン
DWARFは時間の経過とともに進化しており、いくつかのバージョンが存在します。各バージョンは、新しい機能、改善された表現力、または特定のアーキテクチャや言語機能のサポートを追加します。
- DWARF 2: 広く採用された初期のバージョン。
- DWARF 3: DWARF 2の拡張であり、特に64ビットシステムでのアドレス表現の改善、新しい属性とフォームの追加、およびより柔軟なデバッグ情報の表現能力を提供します。このコミットの対象です。
- DWARF 4, DWARF 5: さらに新しいバージョンでは、パフォーマンスの最適化、圧縮、およびより高度なデバッグ機能が導入されています。
DWARFの構造の基本要素
- Compilation Unit (CU): コンパイル単位。通常、単一のソースファイルに対応し、そのファイルに関するすべてのデバッグ情報を含みます。
- Debugging Information Entry (DIE): デバッグ情報エントリ。プログラム内のエンティティ(変数、関数、型など)を記述する構造体です。DIEはツリー構造を形成し、相互に参照し合います。
- Attribute (属性): DIEのプロパティ。例えば、変数の名前、型、メモリ上の位置など。
- Form (フォーム): 属性の値のエンコーディング方法を定義します。例えば、値が定数、文字列、参照、アドレスなど、どのようにバイナリデータとして表現されるかを示します。
DW_FORM_ref_addr
やDW_FORM_addr
などがあります。 - Abbreviation (省略形): 繰り返し現れるDIEの構造を効率的に表現するためのメカニズム。これにより、デバッグ情報のサイズを削減します。
buf
構造体と dataFormat
インターフェース
Goのdebug/dwarf
パッケージでは、DWARFデータを効率的に読み取るためにbuf
構造体が使用されます。このbuf
は、バイトオーダーやアドレスサイズなどのコンテキスト情報を持っていました。このコミットでは、DWARFのバージョンによって異なるデータフォーマットの特性(特に64ビットDWARFかどうかやアドレスサイズ)を抽象化するためにdataFormat
インターフェースが導入されています。
技術的詳細
このコミットの主要な技術的変更点は、DWARF 3のサポートを導入するために、DWARFデータの解析ロジックを更新したことです。特に、以下の点が重要です。
-
dataFormat
インターフェースの導入:- 以前の
buf
構造体はaddrsize int
フィールドを直接持っていました。これは、DWARFデータの読み取り時にアドレスのサイズを決定するために使用されていました。 - DWARF 3では、DWARFフォーマット自体が64ビットであるかどうかの情報(
dwarf64
)や、コンパイル単位ごとのバージョン情報(version
)が重要になります。これらの情報をbuf
に直接持たせるのではなく、dataFormat
という新しいインターフェースを導入し、buf
がこのインターフェースを介してこれらの情報にアクセスするように変更されました。 unit
構造体(コンパイル単位を表す)がこのdataFormat
インターフェースを実装するようになりました。これにより、各コンパイル単位が自身のアドレスサイズ、DWARFバージョン、および64ビットフォーマットであるかどうかの情報を持つことができます。unknownFormat
というダミーの実装も追加され、DWARFのバージョンやアドレスサイズが不明な場合(例えば、アブレビエーションテーブルの解析時など)に使用されます。
- 以前の
-
DW_FORM_ref_addr
の処理の改善:DW_FORM_ref_addr
は、DWARFエントリへの参照を表すフォームです。DWARF 2では、この参照は常にアドレスサイズと同じ長さでしたが、DWARF 3では、DWARFフォーマットが64ビットであるかどうかに応じて、参照のサイズが32ビットまたは64ビットになる可能性があります。- この変更により、
entry.go
のbuf.entry
メソッド内でDW_FORM_ref_addr
を処理する際に、DWARFのバージョンとdwarf64
フラグをチェックし、適切なサイズの値を読み取るようにロジックが追加されました。これにより、DWARF 3で導入された新しい参照形式に正しく対応できるようになりました。
-
コンパイル単位の長さの解析の改善:
unit.go
のparseUnits
関数は、DWARFの.debug_info
セクションからコンパイル単位を解析します。DWARF 2では、コンパイル単位の長さは32ビットの符号なし整数で表現されていましたが、DWARF 3では、64ビットのDWARFフォーマットの場合、長さが0xffffffff
で始まり、その後に64ビットの長さが続くという新しい形式が導入されました。- このコミットでは、この新しい長さのエンコーディングに対応するために、
parseUnits
関数が更新されました。これにより、64ビットのDWARFファイルも正しく解析できるようになります。
-
unit
構造体のフィールド変更:unit
構造体からaddrsize
フィールドが削除され、代わりにasize
(アドレスサイズ)、vers
(バージョン)、is64
(64ビットDWARFフォーマットかどうか)のフィールドが追加されました。これにより、各コンパイル単位が自身のフォーマット特性をより正確に保持できるようになりました。
これらの変更により、Goのdebug/dwarf
パッケージは、DWARF 3で導入された新しいフォーマットの特性を正しく解釈し、デバッグ情報を処理できるようになりました。
コアとなるコードの変更箇所
src/pkg/debug/dwarf/buf.go
buf
構造体からaddrsize
フィールドが削除され、代わりにformat dataFormat
フィールドが追加されました。dataFormat
インターフェースが定義されました。これにはversion()
,dwarf64()
,addrsize()
メソッドが含まれます。unknownFormat
構造体がdataFormat
インターフェースのダミー実装として追加されました。makeBuf
関数のシグネチャが変更され、addrsize
の代わりにdataFormat
を引数として受け取るようになりました。buf.addr()
メソッドがb.addrsize
の代わりにb.format.addrsize()
を使用するように変更されました。
src/pkg/debug/dwarf/entry.go
makeBuf
の呼び出し箇所が、新しいシグネチャに合わせてunknownFormat{}
またはu
(unit) を渡すように変更されました。buf.entry
メソッド内のDW_FORM_ref_addr
の処理ロジックが大幅に拡張されました。DWARFのバージョン (vers
) と64ビットフォーマット (is64
) の情報に基づいて、参照のサイズ (32ビットまたは64ビット) を動的に決定し、適切な値を読み取るようになりました。
src/pkg/debug/dwarf/type.go
makeBuf
の呼び出し箇所が、新しいシグネチャに合わせてunknownFormat{}
を渡すように変更されました。
src/pkg/debug/dwarf/unit.go
unit
構造体からaddrsize
フィールドが削除され、asize
,vers
,is64
フィールドが追加されました。unit
構造体がdataFormat
インターフェースを実装するようになりました。parseUnits
関数が、コンパイル単位の長さの解析ロジックを更新しました。特に、64ビットDWARFフォーマットで導入された0xffffffff
プレフィックスとそれに続く64ビット長に対応するようになりました。parseUnits
関数内で、DWARFのバージョンが2または3であることをチェックするようになりました。unit
構造体のaddrsize
フィールドへの代入がasize
に変更されました。
コアとなるコードの解説
buf.go
の変更
// Data buffer being decoded.
type buf struct {
dwarf *Data
order binary.ByteOrder
format dataFormat // <-- New field
name string
off Offset
data []byte
err error
}
// Data format, other than byte order. This affects the handling of
// certain field formats.
type dataFormat interface {
// DWARF version number. Zero means unknown.
version() int
// 64-bit DWARF format?
dwarf64() (dwarf64 bool, isKnown bool)
// Size of an address, in bytes. Zero means unknown.
addrsize() int
}
// Some parts of DWARF have no data format, e.g., abbrevs.
type unknownFormat struct{}
func (u unknownFormat) version() int { return 0 }
func (u unknownFormat) dwarf64() (bool, bool) { return false, false }
func (u unknownFormat) addrsize() int { return 0 }
func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) addr() uint64 {
switch b.format.addrsize() { // <-- Uses the new interface
case 1:
return uint64(b.uint8())
case 2:
return uint64(b.uint16())
case 4:
return uint64(b.uint32())
case 8:
return b.uint64()
default:
b.error("unknown address size")
return 0
}
}
この変更は、buf
がDWARFデータの解析に必要なコンテキスト(バージョン、64ビットフォーマット、アドレスサイズ)をより汎用的なdataFormat
インターフェースを介して取得するようにします。これにより、異なるDWARFバージョンやフォーマットに対応するための柔軟性が向上します。buf.addr()
は、このインターフェースを通じてアドレスサイズを取得し、適切なバイト数を読み取るようになりました。
entry.go
の DW_FORM_ref_addr
処理
// reference to other entry
case formRefAddr:
vers := b.format.version()
if vers == 0 {
b.error("unknown version for DW_FORM_ref_addr")
} else if vers == 2 {
val = Offset(b.addr())
} else {
is64, known := b.format.dwarf64()
if !known {
b.error("unknown size for DW_FORM_ref_addr")
} else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
}
}
このコードブロックは、DW_FORM_ref_addr
というDWARFフォームの処理を改善しています。これは、他のDWARFエントリへの参照を表します。
- DWARFバージョンが不明 (
vers == 0
) の場合はエラーを報告します。 - DWARFバージョンが2 (
vers == 2
) の場合は、従来通りb.addr()
(アドレスサイズに応じた読み取り)を使用します。 - DWARFバージョンが2より新しい場合(つまりDWARF 3以降)は、
b.format.dwarf64()
を呼び出して、現在のDWARFフォーマットが64ビットであるかどうかをチェックします。- 64ビットフォーマットが不明 (
!known
) の場合はエラーを報告します。 - 64ビットフォーマットである (
is64
) 場合は、64ビットの符号なし整数 (b.uint64()
) を読み取ります。 - それ以外の場合(32ビットフォーマット)は、32ビットの符号なし整数 (
b.uint32()
) を読み取ります。 これにより、DWARF 3で導入されたDW_FORM_ref_addr
の新しいセマンティクス(64ビットDWARFでは64ビット参照)に正しく対応できるようになりました。
- 64ビットフォーマットが不明 (
unit.go
の変更
type unit struct {
base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info
data []byte
atable abbrevTable
asize int // <-- Renamed from addrsize, now part of dataFormat implementation
vers int // <-- New field
is64 bool // <-- New field
}
// Implement the dataFormat interface.
func (u *unit) version() int { return u.vers }
func (u *unit) dwarf64() (bool, bool) { return u.is64, true }
func (u *unit) addrsize() int { return u.asize }
func (d *Data) parseUnits() ([]unit, error) {
// ... (snip) ...
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
if n == 0xffffffff { // <-- DWARF 3 64-bit length handling
u.is64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
if vers != 2 && vers != 3 { // <-- Support for DWARF 3 version check
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
u.vers = int(vers) // <-- Store version
atable, err := d.parseAbbrev(b.uint32())
// ... (snip) ...
u.asize = int(b.uint8()) // <-- Store address size
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}
// ... (snip) ...
}
unit
構造体は、特定のコンパイル単位に関するDWARFのメタデータを保持します。このコミットでは、addrsize
がasize
にリネームされ、さらにvers
(DWARFバージョン)とis64
(64ビットDWARFフォーマットかどうか)が追加されました。これにより、各unit
インスタンスが自身のフォーマット特性を完全に記述できるようになり、dataFormat
インターフェースを実装することが可能になりました。
parseUnits
関数では、コンパイル単位の長さを読み取る際に、0xffffffff
という特殊な値が検出された場合に、続く64ビットの値を実際の長さとして解釈するロジックが追加されました。これはDWARF 3の64ビットフォーマットの仕様に対応するためです。また、サポートするDWARFバージョンが2または3であることを明示的にチェックするようになりました。
これらの変更は、Goのdebug/dwarf
パッケージがDWARF 3の仕様に準拠し、より新しいデバッグ情報ファイルを正確に解析できるようにするために不可欠です。
関連リンク
- Go issue for DWARF 3 support (コミットメッセージに記載されているGoのコードレビューシステムへのリンク)
- DWARF Debugging Information Format Standard (DWARFの公式ウェブサイト)
参考にした情報源リンク
- DWARF Debugging Information Format Standard
- Go source code for debug/dwarf
- Understanding DWARF (DWARFの概要に関する資料)
- DWARF 3 Standard (DWARF 3の公式仕様書)
- Go言語のdebug/dwarfパッケージのコード (Goの公式ドキュメント)
- Go言語のコミット履歴# [インデックス 15840] ファイルの概要
コミット
commit b79afe1b714e225a2b79f639e0956716de34ca64
Author: Ian Lance Taylor <iant@golang.org>
Date: Tue Mar 19 13:59:37 2013 -0700
debug/dwarf: support for DWARF 3
R=rsc
CC=golang-dev
https://golang.org/cl/7662045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b79afe1b714e225a2b79f639e0956716de34ca64
元コミット内容
debug/dwarf
: DWARF 3 のサポート
変更の背景
このコミットは、Go言語のデバッグ情報フォーマットであるDWARFのサポートをDWARFバージョン3に拡張することを目的としています。DWARFは、コンパイラやリンカによって生成される実行可能ファイルに埋め込まれるデバッグ情報のための標準フォーマットです。デバッガは、この情報を使用して、ソースコードレベルでのステップ実行、変数検査、スタックトレースの表示などを行います。
DWARFのバージョンが上がるにつれて、新しい機能や最適化が導入され、より効率的で表現力豊かなデバッグ情報を提供できるようになります。この変更は、Goのツールチェインがより新しいDWARFバージョンを理解し、それを利用できるようにすることで、デバッグ体験の向上や、より新しいコンパイラやリンカとの互換性を確保するために行われました。特に、DWARF 3では、64ビットのアドレスサイズや、より柔軟な参照形式のサポートが強化されており、これに対応することで、より大規模なプログラムや異なるアーキテクチャでのデバッグが改善されます。
DWARF 3.0はDWARF 2.0の上位互換の拡張であり、根本的な変更というよりも機能強化が主です。主な変更点と新機能には以下が含まれます。
- 大規模なデバッグデータファイル: 4GBを超えるデバッグ情報ファイルのサポート。
- 共有ライブラリ参照: 他の共有ライブラリに存在するデバッグ情報エントリを参照する機能。
- 言語サポートの強化: Fortran 90モジュール、C99、Java、Adaの基本的なサポート、C++のネームスペースサポートの強化。
- 型と命名の改善: グローバル型名のためのオプションセクションの追加、名前文字列へのUTF-8の使用、
void *
型の言語非依存な記述方法。 - 最適化されたコードと重複の排除: 最適化されたコードのサポートの改善、重複するデバッグ情報の排除能力の強化。
- インライン関数: DWARF 2にはなかった、インライン関数の呼び出し元での位置を記述する方法の提供。
このコミットは、特にDWARF 3で導入された64ビットフォーマットのサポートと、それに伴うアドレス参照の処理の変更に焦点を当てています。
前提知識の解説
DWARF (Debugging With Attributed Record Formats)
DWARFは、プログラムのデバッグ情報を表現するための標準的なフォーマットです。コンパイルされたバイナリファイルに埋め込まれ、デバッガがソースコードレベルでプログラムの実行を理解し、制御するために必要な情報(変数名、型情報、関数、行番号とアドレスのマッピングなど)を提供します。
DWARFのバージョン
DWARFは時間の経過とともに進化しており、いくつかのバージョンが存在します。各バージョンは、新しい機能、改善された表現力、または特定のアーキテクチャや言語機能のサポートを追加します。
- DWARF 2: 広く採用された初期のバージョン。
- DWARF 3: DWARF 2の拡張であり、特に64ビットシステムでのアドレス表現の改善、新しい属性とフォームの追加、およびより柔軟なデバッグ情報の表現能力を提供します。このコミットの対象です。
- DWARF 4, DWARF 5: さらに新しいバージョンでは、パフォーマンスの最適化、圧縮、およびより高度なデバッグ機能が導入されています。
DWARFの構造の基本要素
- Compilation Unit (CU): コンパイル単位。通常、単一のソースファイルに対応し、そのファイルに関するすべてのデバッグ情報を含みます。
- Debugging Information Entry (DIE): デバッグ情報エントリ。プログラム内のエンティティ(変数、関数、型など)を記述する構造体です。DIEはツリー構造を形成し、相互に参照し合います。
- Attribute (属性): DIEのプロパティ。例えば、変数の名前、型、メモリ上の位置など。
- Form (フォーム): 属性の値のエンコーディング方法を定義します。例えば、値が定数、文字列、参照、アドレスなど、どのようにバイナリデータとして表現されるかを示します。
DW_FORM_ref_addr
やDW_FORM_addr
などがあります。 - Abbreviation (省略形): 繰り返し現れるDIEの構造を効率的に表現するためのメカニズム。これにより、デバッグ情報のサイズを削減します。
buf
構造体と dataFormat
インターフェース
Goのdebug/dwarf
パッケージでは、DWARFデータを効率的に読み取るためにbuf
構造体が使用されます。このbuf
は、バイトオーダーやアドレスサイズなどのコンテキスト情報を持っていました。このコミットでは、DWARFのバージョンによって異なるデータフォーマットの特性(特に64ビットDWARFかどうかやアドレスサイズ)を抽象化するためにdataFormat
インターフェースが導入されています。
技術的詳細
このコミットの主要な技術的変更点は、DWARF 3のサポートを導入するために、DWARFデータの解析ロジックを更新したことです。特に、以下の点が重要です。
-
dataFormat
インターフェースの導入:- 以前の
buf
構造体はaddrsize int
フィールドを直接持っていました。これは、DWARFデータの読み取り時にアドレスのサイズを決定するために使用されていました。 - DWARF 3では、DWARFフォーマット自体が64ビットであるかどうかの情報(
dwarf64
)や、コンパイル単位ごとのバージョン情報(version
)が重要になります。これらの情報をbuf
に直接持たせるのではなく、dataFormat
という新しいインターフェースを導入し、buf
がこのインターフェースを介してこれらの情報にアクセスするように変更されました。 unit
構造体(コンパイル単位を表す)がこのdataFormat
インターフェースを実装するようになりました。これにより、各コンパイル単位が自身のアドレスサイズ、DWARFバージョン、および64ビットフォーマットであるかどうかの情報を持つことができます。unknownFormat
というダミーの実装も追加され、DWARFのバージョンやアドレスサイズが不明な場合(例えば、アブレビエーションテーブルの解析時など)に使用されます。
- 以前の
-
DW_FORM_ref_addr
の処理の改善:DW_FORM_ref_addr
は、DWARFエントリへの参照を表すフォームです。DWARF 2では、この参照は常にアドレスサイズと同じ長さでしたが、DWARF 3では、DWARFフォーマットが64ビットであるかどうかに応じて、参照のサイズが32ビットまたは64ビットになる可能性があります。- この変更により、
entry.go
のbuf.entry
メソッド内でDW_FORM_ref_addr
を処理する際に、DWARFのバージョンとdwarf64
フラグをチェックし、適切なサイズの値を読み取るようにロジックが追加されました。これにより、DWARF 3で導入された新しい参照形式に正しく対応できるようになりました。
-
コンパイル単位の長さの解析の改善:
unit.go
のparseUnits
関数は、DWARFの.debug_info
セクションからコンパイル単位を解析します。DWARF 2では、コンパイル単位の長さは32ビットの符号なし整数で表現されていましたが、DWARF 3では、64ビットのDWARFフォーマットの場合、長さが0xffffffff
で始まり、その後に64ビットの長さが続くという新しい形式が導入されました。- このコミットでは、この新しい長さのエンコーディングに対応するために、
parseUnits
関数が更新されました。これにより、64ビットのDWARFファイルも正しく解析できるようになります。
-
unit
構造体のフィールド変更:unit
構造体からaddrsize
フィールドが削除され、代わりにasize
(アドレスサイズ)、vers
(バージョン)、is64
(64ビットDWARFフォーマットかどうか)のフィールドが追加されました。これにより、各コンパイル単位が自身のフォーマット特性をより正確に保持できるようになりました。
これらの変更により、Goのdebug/dwarf
パッケージは、DWARF 3で導入された新しいフォーマットの特性を正しく解釈し、デバッグ情報を処理できるようになりました。
コアとなるコードの変更箇所
src/pkg/debug/dwarf/buf.go
buf
構造体からaddrsize
フィールドが削除され、代わりにformat dataFormat
フィールドが追加されました。dataFormat
インターフェースが定義されました。これにはversion()
,dwarf64()
,addrsize()
メソッドが含まれます。unknownFormat
構造体がdataFormat
インターフェースのダミー実装として追加されました。makeBuf
関数のシグネチャが変更され、addrsize
の代わりにdataFormat
を引数として受け取るようになりました。buf.addr()
メソッドがb.addrsize
の代わりにb.format.addrsize()
を使用するように変更されました。
src/pkg/debug/dwarf/entry.go
makeBuf
の呼び出し箇所が、新しいシグネチャに合わせてunknownFormat{}
またはu
(unit) を渡すように変更されました。buf.entry
メソッド内のDW_FORM_ref_addr
の処理ロジックが大幅に拡張されました。DWARFのバージョン (vers
) と64ビットフォーマット (is64
) の情報に基づいて、参照のサイズ (32ビットまたは64ビット) を動的に決定し、適切な値を読み取るようになりました。
src/pkg/debug/dwarf/type.go
makeBuf
の呼び出し箇所が、新しいシグネチャに合わせてunknownFormat{}
を渡すように変更されました。
src/pkg/debug/dwarf/unit.go
unit
構造体からaddrsize
フィールドが削除され、asize
,vers
,is64
フィールドが追加されました。unit
構造体がdataFormat
インターフェースを実装するようになりました。parseUnits
関数が、コンパイル単位の長さの解析ロジックを更新しました。特に、64ビットDWARFフォーマットで導入された0xffffffff
プレフィックスとそれに続く64ビット長に対応するようになりました。parseUnits
関数内で、DWARFのバージョンが2または3であることをチェックするようになりました。unit
構造体のaddrsize
フィールドへの代入がasize
に変更されました。
コアとなるコードの解説
buf.go
の変更
// Data buffer being decoded.
type buf struct {
dwarf *Data
order binary.ByteOrder
format dataFormat // <-- New field
name string
off Offset
data []byte
err error
}
// Data format, other than byte order. This affects the handling of
// certain field formats.
type dataFormat interface {
// DWARF version number. Zero means unknown.
version() int
// 64-bit DWARF format?
dwarf64() (dwarf64 bool, isKnown bool)
// Size of an address, in bytes. Zero means unknown.
addrsize() int
}
// Some parts of DWARF have no data format, e.g., abbrevs.
type unknownFormat struct{}
func (u unknownFormat) version() int { return 0 }
func (u unknownFormat) dwarf64() (bool, bool) { return false, false }
func (u unknownFormat) addrsize() int { return 0 }
func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) addr() uint64 {
switch b.format.addrsize() { // <-- Uses the new interface
case 1:
return uint64(b.uint8())
case 2:
return uint64(b.uint16())
case 4:
return uint64(b.uint32())
case 8:
return b.uint64()
default:
b.error("unknown address size")
return 0
}
}
この変更は、buf
がDWARFデータの解析に必要なコンテキスト(バージョン、64ビットフォーマット、アドレスサイズ)をより汎用的なdataFormat
インターフェースを介して取得するようにします。これにより、異なるDWARFバージョンやフォーマットに対応するための柔軟性が向上します。buf.addr()
は、このインターフェースを通じてアドレスサイズを取得し、適切なバイト数を読み取るようになりました。
entry.go
の DW_FORM_ref_addr
処理
// reference to other entry
case formRefAddr:
vers := b.format.version()
if vers == 0 {
b.error("unknown version for DW_FORM_ref_addr")
} else if vers == 2 {
val = Offset(b.addr())
} else {
is64, known := b.format.dwarf64()
if !known {
b.error("unknown size for DW_FORM_ref_addr")
} else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
}
}
このコードブロックは、DW_FORM_ref_addr
というDWARFフォームの処理を改善しています。これは、他のDWARFエントリへの参照を表します。
- DWARFバージョンが不明 (
vers == 0
) の場合はエラーを報告します。 - DWARFバージョンが2 (
vers == 2
) の場合は、従来通りb.addr()
(アドレスサイズに応じた読み取り)を使用します。 - DWARFバージョンが2より新しい場合(つまりDWARF 3以降)は、
b.format.dwarf64()
を呼び出して、現在のDWARFフォーマットが64ビットであるかどうかをチェックします。- 64ビットフォーマットが不明 (
!known
) の場合はエラーを報告します。 - 64ビットフォーマットである (
is64
) 場合は、64ビットの符号なし整数 (b.uint64()
) を読み取ります。 - それ以外の場合(32ビットフォーマット)は、32ビットの符号なし整数 (
b.uint32()
) を読み取ります。 これにより、DWARF 3で導入されたDW_FORM_ref_addr
の新しいセマンティクス(64ビットDWARFでは64ビット参照)に正しく対応できるようになりました。
- 64ビットフォーマットが不明 (
unit.go
の変更
type unit struct {
base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info
data []byte
atable abbrevTable
asize int // <-- Renamed from addrsize, now part of dataFormat implementation
vers int // <-- New field
is64 bool // <-- New field
}
// Implement the dataFormat interface.
func (u *unit) version() int { return u.vers }
func (u *unit) dwarf64() (bool, bool) { return u.is64, true }
func (u *unit) addrsize() int { return u.asize }
func (d *Data) parseUnits() ([]unit, error) {
// ... (snip) ...
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
if n == 0xffffffff { // <-- DWARF 3 64-bit length handling
u.is64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
if vers != 2 && vers != 3 { // <-- Support for DWARF 3 version check
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
u.vers = int(vers) // <-- Store version
atable, err := d.parseAbbrev(b.uint32())
// ... (snip) ...
u.asize = int(b.uint8()) // <-- Store address size
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}
// ... (snip) ...
}
unit
構造体は、特定のコンパイル単位に関するDWARFのメタデータを保持します。このコミットでは、addrsize
がasize
にリネームされ、さらにvers
(DWARFバージョン)とis64
(64ビットDWARFフォーマットかどうか)が追加されました。これにより、各unit
インスタンスが自身のフォーマット特性を完全に記述できるようになり、dataFormat
インターフェースを実装することが可能になりました。
parseUnits
関数では、コンパイル単位の長さを読み取る際に、0xffffffff
という特殊な値が検出された場合に、続く64ビットの値を実際の長さとして解釈するロジックが追加されました。これはDWARF 3の64ビットフォーマットの仕様に対応するためです。また、サポートするDWARFバージョンが2または3であることを明示的にチェックするようになりました。
これらの変更は、Goのdebug/dwarf
パッケージがDWARF 3の仕様に準拠し、より新しいデバッグ情報ファイルを正確に解析できるようにするために不可欠です。
関連リンク
- Go issue for DWARF 3 support (コミットメッセージに記載されているGoのコードレビューシステムへのリンク)
- DWARF Debugging Information Format Standard (DWARFの公式ウェブサイト)
参考にした情報源リンク
- DWARF Debugging Information Format Standard
- Go source code for debug/dwarf
- Understanding DWARF (DWARFの概要に関する資料)
- DWARF 3 Standard (DWARF 3の公式仕様書)
- Go言語のdebug/dwarfパッケージのコード (Goの公式ドキュメント)
- Go言語のコミット履歴