[インデックス 14406] ファイルの概要
このコミットは、Go言語の標準ライブラリであるdebug/elf
パッケージにおけるバグ修正と、それに関連するテストの改善、およびドキュメントの更新を含んでいます。
変更されたファイルは以下の通りです。
doc/go1.1.html
: Go 1.1のリリースノートにdebug/elf
パッケージの変更に関する説明が追加されました。src/pkg/debug/elf/file.go
: ELFファイルのシンボルテーブルを読み込む際に、最初のシンボルをスキップする処理が削除されました。src/pkg/debug/elf/file_test.go
: ELFファイルのデバッグ情報(DWARF)のリロケーションテストが拡張され、新しいテストケースが追加されました。src/pkg/debug/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
: 新しいバイナリテストデータファイルが追加されました。
コミット
debug/elf: do not skip first symbol in the symbol table
Do not skip the first symbol in the symbol table. Any other indexes
into the symbol table (for example, indexes in relocation entries)
will now refer to the symbol following the one that was intended.
Add an object that contains debug relocations, which debug/dwarf
failed to decode correctly. Extend the relocation tests to cover
this case.
Note that the existing tests passed since the symbol following the
symbol that required relocation is also of type STT_SECTION.
Fixes #4107.
R=golang-dev, mikioh.mikioh, iant, iant
CC=golang-dev
https://golang.org/cl/6848044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/76689845e331d32c94d77280c34fb92e7dde79ba
元コミット内容
debug/elf: do not skip first symbol in the symbol table
Do not skip the first symbol in the symbol table. Any other indexes
into the symbol table (for example, indexes in relocation entries)
will now refer to the symbol following the one that was intended.
Add an object that contains debug relocations, which debug/dwarf
failed to decode correctly. Extend the relocation tests to cover
this case.
Note that the existing tests passed since the symbol following the
symbol that required relocation is also of type STT_SECTION.
Fixes #4107.
R=golang-dev, mikioh.mikioh, iant, iant
CC=golang-dev
https://golang.org/cl/6848044
変更の背景
このコミットは、Go言語のdebug/elf
パッケージがELF(Executable and Linkable Format)ファイルのシンボルテーブルを解析する際に、最初のシンボルエントリを誤ってスキップしていたバグを修正するために行われました。
ELFファイルのシンボルテーブルの最初の要素(インデックス0)は、慣例的に「NULLシンボル」または「未定義シンボル」として予約されており、通常はすべてのフィールドがゼロで埋められています。多くのツールやライブラリは、このNULLシンボルを特別扱いし、実質的なシンボルとしては扱わないことがあります。
しかし、debug/elf
パッケージがこの最初のシンボルをスキップしてシンボルリストを生成していたため、シンボルテーブル内の他のエントリ(例えば、リロケーションエントリが参照するシンボルインデックス)が、本来参照すべきシンボルから一つずれてしまうという問題が発生していました。特に、デバッグ情報(DWARF)の解析において、リロケーションエントリがシンボルテーブルのインデックスを参照する場合、このずれが原因で誤ったシンボルが参照され、デバッグ情報のデコードが正しく行われない可能性がありました。
この問題は、Go Issue #4107として報告されており、このコミットはその修正を目的としています。既存のテストではこのバグが検出されなかったのは、たまたま誤って参照された「ずれた先のシンボル」が、本来参照すべきシンボルと同じSTT_SECTION
タイプであったため、テストがパスしてしまっていたという偶然の要因がありました。このコミットでは、この特定のケースを捕捉するための新しいテストデータとテストロジックも追加されています。
前提知識の解説
ELF (Executable and Linkable Format)
ELFは、Unix系システム(Linux、BSD、Solarisなど)で広く使用されている、実行可能ファイル、オブジェクトファイル、共有ライブラリ、コアダンプなどのバイナリファイルを表現するための標準的なファイルフォーマットです。ELFファイルは、プログラムのコード、データ、デバッグ情報、シンボルテーブル、リロケーション情報など、様々なセクションで構成されています。
- セクション (Sections): ELFファイル内の論理的なデータブロック。例えば、
.text
(コード)、.data
(初期化済みデータ)、.bss
(初期化されていないデータ)、.symtab
(シンボルテーブル)、.rela.text
(テキストセクションのリロケーション)などがあります。 - シンボルテーブル (Symbol Table): プログラム内のシンボル(関数名、変数名、セクション名など)とそのアドレス、サイズ、型、バインディングなどの情報が格納されているセクション(通常は
.symtab
または.dynsym
)。リンカがプログラムの異なる部分を結合する際に使用します。- NULLシンボル: ELFシンボルテーブルのインデックス0は、常に特別な「NULLシンボル」として予約されています。このシンボルは、未定義のシンボルや、特定のセクションを参照しないリロケーションエントリなどで使用されます。通常、その名前は空文字列で、値やサイズもゼロです。
- リロケーションエントリ (Relocation Entries): プログラムがメモリにロードされる際に、アドレスを修正する必要がある箇所を示す情報です。例えば、ある関数が別のモジュール内の関数を呼び出す場合、その呼び出し命令のアドレスはリンク時に決定されるため、リロケーションエントリが必要になります。リロケーションエントリは、通常、シンボルテーブル内の特定のシンボルをインデックスで参照します。
R_X86_64_PC32
のようなリロケーションタイプは、特定のアーキテクチャとリロケーションの種類を示します。
- セクションヘッダテーブル (Section Header Table): ELFファイル内の各セクションに関するメタデータ(名前、タイプ、アドレス、サイズ、ファイルオフセットなど)が格納されています。
DWARF (Debugging With Attributed Record Formats)
DWARFは、ソースレベルデバッガがプログラムの実行をデバッグするために必要な情報(変数名、型、関数名、ソースコードの行番号、スタックフレーム情報など)をバイナリファイルに格納するための標準的なフォーマットです。ELFファイルの場合、DWARF情報は通常、.debug_info
、.debug_abbrev
、.debug_line
などの専用のデバッグセクションに格納されます。
DWARF情報は、しばしばELFシンボルテーブル内のシンボルを参照します。例えば、ある変数のデバッグ情報が、その変数が定義されているセクションや、関連する関数シンボルを参照するために、ELFシンボルテーブルのインデックスを使用することがあります。
Go言語のdebug/elf
およびdebug/dwarf
パッケージ
debug/elf
: Go言語でELFファイルを解析するためのパッケージです。ELFファイルのヘッダ、セクション、シンボルテーブル、リロケーションエントリなどを読み込み、Goのデータ構造にマッピングする機能を提供します。debug/dwarf
: Go言語でDWARFデバッグ情報を解析するためのパッケージです。debug/elf
パッケージなどによって読み込まれたELFファイル内のDWARFセクションから、ソースコードの行情報、変数情報、型情報などを抽出します。
これらのパッケージは、Goのツールチェイン(例えば、デバッガやプロファイラ)がバイナリファイルを解析し、デバッグ情報やプロファイリング情報を取得するために不可欠です。
技術的詳細
このコミットの技術的詳細を理解するためには、debug/elf
パッケージがシンボルテーブルをどのように処理していたか、そしてその変更がどのように影響するかを掘り下げます。
従来のdebug/elf
の動作と問題点
debug/elf
パッケージのFile
構造体には、ELFファイルのシンボルテーブルを読み込むためのメソッド(例: getSymbols32
, getSymbols64
)が存在します。これらのメソッドは、シンボルテーブルのセクションからバイトデータを読み込み、それをSymbol
構造体のスライスに変換します。
従来のコードでは、シンボルテーブルを読み込む際に、以下のような処理が含まれていました。
// The first entry is all zeros.
var skip [Sym32Size]byte
symtab.Read(skip[0:])
または
// The first entry is all zeros.
var skip [Sym64Size]byte
symtab.Read(skip[0:])
このコードは、シンボルテーブルの最初のSym32Size
バイト(またはSym64Size
バイト)を読み飛ばすことを意図していました。コメントにあるように、「最初のエントリはすべてゼロ」であるという慣例に基づき、NULLシンボルを無視しようとしていたと考えられます。
しかし、この「スキップ」処理が問題を引き起こしました。debug/elf
パッケージが外部に公開するシンボルリスト(Symbols()
やImportedSymbols()
メソッドで返されるもの)は、このスキップされた状態のシンボルテーブルに基づいていました。その結果、Goのコード内でシンボルテーブルのインデックスを使用する際(特にdebug/dwarf
パッケージがELFファイル内のリロケーションエントリやその他のデバッグ情報からシンボルを参照する場合)、Goのシンボルリストのインデックスと、ELFファイル本来のシンボルテーブルのインデックスとの間に「1」のずれが生じていました。
例えば、ELFファイル内のリロケーションエントリがシンボルテーブルのインデックスN
を参照している場合、debug/elf
が生成したシンボルリストでは、そのインデックスN
はELFファイル本来のインデックスN+1
のシンボルを指してしまいます。これにより、デバッグ情報が正しく解決されず、デバッガが誤った情報を提供したり、クラッシュしたりする可能性がありました。
既存テストがバグを検出できなかった理由
コミットメッセージに「Note that the existing tests passed since the symbol following the symbol that required relocation is also of type STT_SECTION.」とあるように、既存のテストではこのバグが顕在化しませんでした。これは、たまたまリロケーションが必要なシンボルの「次」のシンボル(つまり、誤って参照されてしまうシンボル)が、本来参照すべきシンボルと同じSTT_SECTION
タイプであったためです。STT_SECTION
は、シンボルがセクションに関連付けられていることを示すタイプであり、このタイプであれば、たとえシンボルがずれていても、特定の文脈では処理が偶然成功してしまうことがありました。この偶然の一致が、バグの発見を遅らせる原因となりました。
修正内容
このコミットの主要な修正は、src/pkg/debug/elf/file.go
内のgetSymbols32
およびgetSymbols64
関数から、最初のシンボルをスキップする上記のコードを削除することです。これにより、debug/elf
が提供するシンボルリストのインデックスが、ELFファイル本来のシンボルテーブルのインデックスと完全に一致するようになります。
テストの改善
バグの再発を防ぎ、より堅牢な解析を保証するために、src/pkg/debug/elf/file_test.go
内のテストが大幅に拡張されました。
relocationTest
構造体の変更: 以前は単一のfirstEntry
しか検証していませんでしたが、entries []relocationTestEntry
というスライスを持つように変更されました。これにより、一つのテストファイル内で複数の異なるDWARFエントリを検証できるようになりました。- 新しいテストデータ:
testdata/gcc-amd64-openbsd-debug-with-rela.obj
という新しいバイナリファイルが追加されました。このファイルは、debug/dwarf
が以前正しくデコードできなかったデバッグリロケーションを含むオブジェクトファイルであり、今回の修正が正しく機能するかを検証するための重要なテストケースとなります。 TestDWARFRelocations
関数のロジック変更:- 以前は
reader.Next()
を一度だけ呼び出し、最初のDWARFエントリのみを検証していました。 - 修正後は、
test.entries
スライスをループし、各relocationTestEntry
で指定されたentryNumber
までreader.Next()
を繰り返し呼び出してスキップし、目的のDWARFエントリを正確に取得して検証するようになりました。これにより、特定のインデックスにあるDWARFエントリが正しく解析されることを確認できます。
- 以前は
影響
この修正により、debug/elf
パッケージが返すシンボルリストのインデックスが変更されます。以前のバージョンでは、インデックスN
はELFファイルの元のインデックスN+1
のシンボルを指していましたが、修正後はインデックスN
がELFファイルの元のインデックスN
のシンボルを指すようになります。
この変更は、debug/elf
のSymbols()
またはImportedSymbols()
関数を呼び出し、その結果のシンボルリストのインデックスに依存している既存のコードに影響を与える可能性があります。特に、シンボルインデックスを直接使用してELFファイル内の他の情報(例えば、リロケーションエントリ)を解決しているようなコードは、この変更に合わせて調整が必要になる場合があります。この点はdoc/go1.1.html
の更新で明記されています。
コアとなるコードの変更箇所
src/pkg/debug/elf/file.go
getSymbols32
関数とgetSymbols64
関数から、シンボルテーブルの最初の要素をスキップする以下のコードが削除されました。
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -417,10 +417,6 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
- // The first entry is all zeros.
- var skip [Sym32Size]byte
- symtab.Read(skip[0:])
-
symbols := make([]Symbol, symtab.Len()/Sym32Size)
i := 0
@@ -460,10 +456,6 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
- // The first entry is all zeros.
- var skip [Sym64Size]byte
- symtab.Read(skip[0:])
-
symbols := make([]Symbol, symtab.Len()/Sym664Size)
i := 0
src/pkg/debug/elf/file_test.go
relocationTest
構造体が変更され、複数のテストエントリを保持できるようになりました。また、新しいテストケースが追加され、TestDWARFRelocations
関数が複数のエントリを検証するように修正されました。
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -175,23 +175,41 @@ func TestOpen(t *testing.T) {
}
}
+type relocationTestEntry struct {
+ entryNumber int
+ entry *dwarf.Entry
+}
+
type relocationTest struct {
- file string
- firstEntry *dwarf.Entry
+ file string
+ entries []relocationTestEntry
}
var relocationTests = []relocationTest{
{
"testdata/go-relocation-test-gcc441-x86-64.obj",
- &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ []relocationTestEntry{
+ {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+ },
},
{
"testdata/go-relocation-test-gcc441-x86.obj",
- &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName: Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ []relocationTestEntry{
+ {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+ },
},
{
"testdata/go-relocation-test-gcc424-x86-64.obj",
- &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ []relocationTestEntry{
+ {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+ },
+ },
+ {
+ "testdata/gcc-amd64-openbsd-debug-with-rela.obj",
+ []relocationTestEntry{
+ {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}}},
+ {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrAttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}}},
+ },
},
}
@@ -207,20 +225,24 @@ func TestDWARFRelocations(t *testing.T) {
t.Error(err)
continue
}
- reader := dwarf.Reader()
- // Checking only the first entry is sufficient since it has
- // many different strings. If the relocation had failed, all
- // the string offsets would be zero and all the strings would
- // end up being the same.
- firstEntry, err := reader.Next()
- if err != nil {
- t.Error(err)
- continue
- }
-
- if !reflect.DeepEqual(test.firstEntry, firstEntry) {
- t.Errorf("#%d: mismatch: got:%#v want:%#v", i, firstEntry, test.firstEntry)
- continue
+ for _, testEntry := range test.entries {
+ reader := dwarf.Reader()
+ for j := 0; j < testEntry.entryNumber; j++ {
+ entry, err := reader.Next()
+ if entry == nil || err != nil {
+ t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
+ continue
+ }
+ }
+ entry, err := reader.Next()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(testEntry.entry, entry) {
+ t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
+ continue
+ }
}
}
}
コアとなるコードの解説
src/pkg/debug/elf/file.go
の変更
このファイルでは、File
構造体のメソッドであるgetSymbols32
とgetSymbols64
から、シンボルテーブルの最初の要素を読み飛ばすためのコードが削除されました。
- 削除されたコードの意図: 以前のコードは、ELFシンボルテーブルのインデックス0が常にNULLシンボルであるという慣例に基づき、そのNULLシンボルをGoのシンボルリストから除外しようとしていました。
- 削除の理由: このスキップ処理が、
debug/elf
パッケージが提供するシンボルリストのインデックスと、ELFファイル本来のシンボルテーブルのインデックスとの間にずれを生じさせていました。特に、DWARFデバッグ情報がELFシンボルテーブルのインデックスを直接参照する場合に、このずれが問題を引き起こしていました。 - 変更の影響: この変更により、
debug/elf
パッケージが返すシンボルリストは、ELFファイル内のシンボルテーブルと1対1で対応するようになります。つまり、GoのシンボルリストのインデックスN
は、ELFファイル内のシンボルテーブルのインデックスN
のシンボルを正確に指すようになります。これにより、デバッグ情報の解析におけるシンボル参照の整合性が保たれます。
src/pkg/debug/elf/file_test.go
の変更
このファイルでは、TestDWARFRelocations
テスト関数と関連するデータ構造が大幅に強化されました。
-
relocationTestEntry
構造体の追加:type relocationTestEntry struct { entryNumber int entry *dwarf.Entry }
この新しい構造体は、テスト対象のDWARFエントリが、そのDWARFリーダーから何番目のエントリであるか(
entryNumber
)と、期待されるDWARFエントリのデータ(entry
)を保持します。これにより、テストが特定のDWARFエントリを正確にターゲットにできるようになります。 -
relocationTest
構造体の変更:type relocationTest struct { file string entries []relocationTestEntry }
以前は
firstEntry *dwarf.Entry
というフィールドしか持っていませんでしたが、entries []relocationTestEntry
というスライスを持つように変更されました。これにより、一つのテストファイル(例:testdata/go-relocation-test-gcc441-x86-64.obj
)に対して、複数の異なるDWARFエントリを検証できるようになりました。これは、より包括的なテストを可能にします。 -
新しいテストケースの追加:
{ "testdata/gcc-amd64-openbsd-debug-with-rela.obj", []relocationTestEntry{ {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}}}, {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}}}, }, },
この新しいテストケースは、
debug/dwarf
が以前正しくデコードできなかった特定のデバッグリロケーションを含むオブジェクトファイル(gcc-amd64-openbsd-debug-with-rela.obj
)を対象としています。このテストケースは、it_interval
とit_value
という2つの特定のDWARFメンバーエントリが正しく解析されることを検証します。entryNumber
が203と204であることから、これらのエントリがDWARF情報内でかなり後方にあることが示唆されており、以前の「最初の要素のみをチェックする」テストでは捕捉できなかった種類のバグを検出するのに役立ちます。 -
TestDWARFRelocations
関数の検証ロジックの変更:for _, testEntry := range test.entries { reader := dwarf.Reader() for j := 0; j < testEntry.entryNumber; j++ { entry, err := reader.Next() if entry == nil || err != nil { t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err) continue } } entry, err := reader.Next() if err != nil { t.Error(err) continue } if !reflect.DeepEqual(testEntry.entry, entry) { t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry) continue } }
以前は、
dwarf.Reader()
から取得した最初のDWARFエントリのみを検証していました。しかし、新しいロジックでは、test.entries
スライス内の各relocationTestEntry
についてループします。- 内部の
for j := 0; j < testEntry.entryNumber; j++
ループは、目的のentryNumber
に到達するまでreader.Next()
を繰り返し呼び出し、不要なDWARFエントリをスキップします。 - その後、目的のDWARFエントリを読み込み、
reflect.DeepEqual
を使用して、期待されるdwarf.Entry
と実際に読み込まれたエントリが完全に一致するかどうかを検証します。 この変更により、テストは特定のDWARFエントリが正しく解析されることを、その位置に関わらず確認できるようになり、より堅牢なデバッグ情報解析の検証が可能になりました。
- 内部の
関連リンク
- Go Issue #4107: https://github.com/golang/go/issues/4107
このコミットが修正したバグの元の報告です。
debug/elf
のシンボルテーブルインデックスが1つずれている問題について議論されています。
参考にした情報源リンク
- ELF (Executable and Linkable Format) - Wikipedia: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
- DWARF - Wikipedia: https://en.wikipedia.org/wiki/DWARF
- Go
debug/elf
package documentation: https://pkg.go.dev/debug/elf - Go
debug/dwarf
package documentation: https://pkg.go.dev/debug/dwarf - System V Application Binary Interface - DRAFT - 4.1. Symbol Table: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/symtab.html ELFシンボルテーブルの最初の要素(インデックス0)がNULLシンボルであることに関する情報。