Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18833] ファイルの概要

このコミットは、Go言語のデバッグ情報パッケージ debug/dwarf に、マルチファイル圧縮ツールである .dwz (DWARF With Zlib) が使用する新しいDWARFフォーム (DW_FORM_GNU_ref_alt および DW_FORM_GNU_strp_alt) のサポートを追加するものです。これにより、Goのバイナリが生成するDWARFデバッグ情報が、.dwz ツールによって効率的に圧縮・最適化されるようになります。

コミット

commit 5b5c8f0576e15db9bc5aa1e63507cef3aa370478
Author: Dhiru Kholia <dhiru.kholia@gmail.com>
Date:   Tue Mar 11 18:49:50 2014 -0700

    dwarf: add extensions for multi-file compression (.dwz)
    
    LGTM=iant
    R=golang-codereviews, iant, bradfitz
    CC=golang-codereviews, math-nuts
    https://golang.org/cl/72820044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/5b5c8f0576e15db9bc5aa1e63507cef3aa370478

元コミット内容

--- a/src/pkg/debug/dwarf/const.go
+++ b/src/pkg/debug/dwarf/const.go
@@ -212,6 +212,10 @@ const (
 	formExprloc     format = 0x18
 	formFlagPresent format = 0x19
 	formRefSig8     format = 0x20
+	// Extensions for multi-file compression (.dwz)
+	// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
+	formGnuRefAlt  format = 0x1f20
+	formGnuStrpAlt format = 0x1f21
 )
 
 // A Tag is the classification (the type) of an Entry.
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
index 934416e6c1..665c6840d4 100644
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/debug/dwarf/entry.go
@@ -241,10 +241,10 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
 		// 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:
+		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
 			is64, known := b.format.dwarf64()
 			if !known {
-				b.error("unknown size for DW_FORM_sec_offset")
+				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))\n
 			} else if is64 {
 				val = int64(b.uint64())
 			} else {

変更の背景

この変更の背景には、コンパイルされたバイナリに含まれるデバッグ情報のサイズを削減したいというニーズがあります。特に、大規模なソフトウェアプロジェクトや、多くの共有ライブラリを使用するシステムでは、デバッグ情報が非常に大きくなり、ディスクスペースの消費や配布時の帯域幅の増加といった問題を引き起こします。

DWARF (Debugging With Arbitrary Record Formats) は、コンパイラが生成するデバッグ情報の標準フォーマットであり、デバッガが実行中のプログラムのソースコードレベルでの情報を理解するために不可欠です。しかし、DWARF情報は冗長になりがちで、特に複数のバイナリが共通のデバッグ情報を共有する場合に重複が多く発生します。

.dwz ツールは、このようなDWARFデバッグ情報の重複を排除し、圧縮することで、デバッグシンボルの全体的なサイズを大幅に削減することを目的としています。.dwz は、複数の実行ファイルや共有ライブラリを分析し、共通のデバッグ情報を抽出し、それを単一の分離されたELFオブジェクトファイルに移動します。元のバイナリは、この共通ファイルを参照するように変更されます。このプロセスを効率的に行うために、.dwz は標準のDWARFフォームに加えて、独自の拡張フォームを使用します。

Go言語のツールチェインが生成するバイナリのデバッグ情報が、このような外部ツールによって最適化されるためには、Goの debug/dwarf パッケージがこれらの拡張フォームを正しく解釈できる必要があります。このコミットは、そのための基盤を整備するものです。

前提知識の解説

DWARF (Debugging With Arbitrary Record Formats)

DWARFは、コンパイルされたプログラムのデバッグ情報を表現するための標準的なフォーマットです。デバッガはDWARF情報を使用して、ソースコードの行番号、変数名、関数名、型情報、スタックフレームの構造などを理解し、ユーザーがソースコードレベルでプログラムをデバッグできるようにします。

DWARF情報は、通常、実行可能ファイルや共有ライブラリの .debug_info.debug_abbrev.debug_str などのセクションに格納されます。

DWARF Forms (DW_FORM_*)

DWARF情報は、属性と値のペアで構成されます。各属性には、その値の形式("form")を示す DW_FORM_* コードが関連付けられています。例えば、DW_FORM_addr はアドレス値を、DW_FORM_data4 は4バイトのデータを表します。これらのフォームは、デバッグ情報のエンコーディングとデコーディングの方法を定義します。

.dwz (DWARF With Zlib)

.dwz は、DWARFデバッグ情報を最適化および圧縮するためのユーティリティです。主な機能は以下の通りです。

  1. 重複排除: 複数のバイナリ間で共通するデバッグ情報(重複するDWARF情報エントリ、文字列、マクロ記述など)を特定し、排除します。
  2. マルチファイル圧縮: 共通のデバッグ情報を単一の共有ファイル(通常は .dwz 拡張子を持つ)に移動し、元のバイナリは軽量な参照を持つように変更されます。これにより、個々のバイナリのデバッグ情報サイズが削減され、システム全体のデバッグ情報フットプリントが小さくなります。
  3. 圧縮: 内部的にZlibなどの圧縮アルゴリズムを使用して、デバッグ情報自体を圧縮します。

.dwz は、特にLinuxディストリビューションなどで、デバッグ情報パッケージのサイズを削減するために広く利用されています。

DWARF Issue 120604.1

このコミットのコメントに記載されている http://www.dwarfstd.org/ShowIssue.php?issue=120604.1 は、DWARF標準化委員会で議論された特定の課題(Issue)を指しています。このIssueは、.dwz のようなツールが使用する「代替ファイルへの参照」を表現するための新しいDWARFフォームの必要性に関するものでした。具体的には、DW_FORM_GNU_ref_altDW_FORM_GNU_strp_alt の導入が提案され、議論されました。これらは、標準のDWARF形式では表現できない、外部の共有デバッグ情報ファイルへの参照を可能にするための拡張です。

技術的詳細

このコミットは、Goの debug/dwarf パッケージが .dwz ツールによって生成される可能性のある非標準のDWARFフォームを認識し、処理できるようにするためのものです。

具体的には、以下の2つの新しいDWARFフォームが src/pkg/debug/dwarf/const.go に追加されています。

  • formGnuRefAlt (値: 0x1f20): これは DW_FORM_GNU_ref_alt に対応します。このフォームは、別のデバッグ情報ファイル(通常は .dwz によって生成された共有デバッグ情報ファイル)内のDWARF情報エントリへの参照を表します。これにより、デバッグ情報が複数のファイルに分散している場合でも、デバッガが正しい情報を追跡できるようになります。
  • formGnuStrpAlt (値: 0x1f21): これは DW_FORM_GNU_strp_alt に対応します。このフォームは、別のデバッグ情報ファイル内の文字列テーブルへの参照を表します。.dwz は重複する文字列を共有ファイルに移動するため、このフォームは、元のバイナリがその共有ファイル内の文字列を参照するために必要となります。

これらのフォームは、標準のDWARF仕様には含まれていませんが、GNUツールチェインや .dwz のようなツールによって拡張として使用されます。

src/pkg/debug/dwarf/entry.go の変更は、これらの新しいフォームが formSecOffset と同様にセクションオフセットとして扱われることを示しています。formSecOffset は、DWARF 4で導入されたセクション参照の新しい形式であり、以前の formData4formData8 の使用を置き換えるものです。formGnuRefAltformGnuStrpAlt も同様に、参照先のセクション内のオフセットとして解釈されるため、同じ処理パスに追加されています。

エラーメッセージの変更は、未知のフォームに遭遇した場合に、より具体的な16進数形式のフォーム値を出力するように改善されています。これにより、デバッグ時にどのフォームが問題を引き起こしているのかを特定しやすくなります。

コアとなるコードの変更箇所

src/pkg/debug/dwarf/const.go

 	formExprloc     format = 0x18
 	formFlagPresent format = 0x19
 	formRefSig8     format = 0x20
+	// Extensions for multi-file compression (.dwz)
+	// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
+	formGnuRefAlt  format = 0x1f20
+	formGnuStrpAlt format = 0x1f21
 )

src/pkg/debug/dwarf/entry.go

 		// 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:
+		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
 			is64, known := b.format.dwarf64()
 			if !known {
-				b.error("unknown size for DW_FORM_sec_offset")
+				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
 			} else if is64 {
 				val = int64(b.uint64())
 			} else {

コアとなるコードの解説

src/pkg/debug/dwarf/const.go の変更

このファイルでは、DWARFの各種定数、特に format 型(DWARFフォームを表す)が定義されています。 追加された formGnuRefAltformGnuStrpAlt は、それぞれ 0x1f200x1f21 という16進数の値を持つ新しい定数として定義されています。これらの値は、DWARF標準の拡張としてGNUツールチェインが使用する特定のフォームコードに対応しています。コメントで示されているように、これらは .dwz のようなマルチファイル圧縮ツールが使用する拡張であり、DWARF標準化委員会で議論されたIssue 120604.1に関連しています。

src/pkg/debug/dwarf/entry.go の変更

このファイルには、DWARFエントリを解析するためのロジックが含まれています。entry メソッドは、DWARF情報エントリの属性を読み取る際に、その属性のフォームに基づいて値を解釈します。

元のコードでは、formSecOffset (セクションオフセットを表すフォーム) のみを処理していました。このコミットでは、case ステートメントに formGnuRefAltformGnuStrpAlt が追加されています。これは、これらの新しいGNU拡張フォームも formSecOffset と同様に、セクション内のオフセットとして扱われるべきであることを意味します。つまり、debug/dwarf パッケージは、これらのフォームに遭遇した場合、それが指す値がセクション内のオフセットであると認識し、そのオフセットを読み取って処理を続行します。

エラーメッセージの変更 (b.error("unknown size for DW_FORM_sec_offset") から b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))) は、より汎用的なエラー報告を可能にします。これにより、将来的に他の未知のフォームに遭遇した場合でも、具体的なフォームの16進数値をエラーメッセージに含めることができ、デバッグが容易になります。

関連リンク

参考にした情報源リンク