[インデックス 18714] ファイルの概要
コミット
commit ebe1eb6537d4873863db4a526250a0e5ddab41b2
Author: Graham King <graham4king@gmail.com>
Date: Mon Mar 3 11:11:04 2014 -0800
cmd/ld: DWARF opcode base to 10
DWARF 2 has 9 standard opcodes, so dwarfdump expects us to use an
opcode base of at least 10. Previously we used 5.
Discussion:
https://groups.google.com/forum/#!topic/golang-dev/d-BqpPgalzc
LGTM=josharian, rsc
R=golang-codereviews, gobot, rsc, josharian, iant, bradfitz
CC=golang-codereviews
https://golang.org/cl/69320043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ebe1eb6537d4873863db4a526250a0e5ddab41b2
元コミット内容
cmd/ld: DWARF opcode base to 10
このコミットは、Goリンカ(cmd/ld
)におけるDWARFデバッグ情報の生成において、オペコードのベース値を5から10に変更するものです。
変更の背景
この変更の背景には、DWARF 2仕様とdwarfdump
ユーティリティの期待値との不整合がありました。DWARF (Debugging With Attributed Record Formats) は、コンパイラが生成するデバッグ情報の標準フォーマットであり、デバッガが実行ファイル内のアドレスをソースコードのファイル名、行番号、変数情報などにマッピングするために使用されます。
DWARFのラインナンバープログラム(Line Number Program)は、ソースコードの行と実行ファイルの命令アドレスとのマッピングを記述するために使用されます。このプログラムは、特別なオペコードと標準オペコードで構成されます。DWARF 2仕様では、標準オペコードの数が9つと定義されており、dwarfdump
のようなDWARFデバッグ情報を解析するツールは、この標準オペコードの数に基づいてオペコードのベース値を期待します。
Goリンカは以前、このオペコードのベース値を5としていました。しかし、dwarfdump
はDWARF 2の9つの標準オペコードを正しく解釈するために、オペコードのベース値が少なくとも10であることを期待していました。この不整合により、Goリンカが生成したDWARF情報がdwarfdump
で正しく解析されない、あるいは警告が表示されるといった問題が発生していました。このコミットは、この問題を解決し、Goが生成するDWARF情報がより広範なツールと互換性を持つようにするために行われました。
前提知識の解説
-
DWARF (Debugging With Attributed Record Formats): DWARFは、プログラムのデバッグ情報を表現するための標準的なフォーマットです。コンパイラはソースコードをコンパイルする際に、変数、関数、型、ソースファイルの行番号と実行可能コードのアドレスのマッピングなどのデバッグ情報を生成し、これを実行ファイルに埋め込みます。デバッガはこのDWARF情報を読み取り、ユーザーがソースコードレベルでプログラムをデバッグできるようにします。
-
Goリンカ (
cmd/ld
): Go言語のビルドプロセスにおいて、cmd/ld
はGoコンパイラによって生成されたオブジェクトファイルを結合し、最終的な実行可能バイナリを生成する役割を担うリンカです。このリンカは、デバッグ情報(DWARF)の生成と、それをバイナリに埋め込む処理も行います。 -
DWARF Line Number Program: DWARFのデバッグ情報の一部として、ラインナンバープログラムがあります。これは、ソースコードの特定の行が、コンパイルされたバイナリのどの命令アドレスに対応するかを記述するためのバイトコードのシーケンスです。デバッガはこれを利用して、実行中のプログラムの現在の命令がソースコードのどの行に相当するかを特定し、ブレークポイントの設定やステップ実行を可能にします。
-
オペコード (Opcode): オペコードは、ラインナンバープログラム内で特定の操作を指示するバイトコードです。DWARFのラインナンバープログラムには、標準オペコードと特別なオペコードがあります。標準オペコードは、行番号やアドレスのインクリメントなど、一般的な操作を表現します。特別なオペコードは、より効率的に行番号とアドレスの変更を表現するために使用されます。
-
オペコードベース (Opcode Base): DWARFのラインナンバープログラムにおいて、
opcode_base
は特別なオペコードの開始値を定義します。標準オペコードは1からopcode_base - 1
までの値を取ります。つまり、opcode_base
の値が大きいほど、より多くの標準オペコードが利用可能であることを意味します。 -
dwarfdump
:dwarfdump
は、実行ファイルやオブジェクトファイルに含まれるDWARFデバッグ情報を解析し、人間が読める形式で表示するためのコマンドラインユーティリティです。デバッグ情報が正しく生成されているかを確認したり、デバッグ情報の構造を分析したりする際に使用されます。
技術的詳細
DWARFのラインナンバープログラムは、ステートマシンとして動作します。このステートマシンは、ソースファイルの行番号、命令アドレス、列番号などの状態を保持し、オペコードを処理することでこれらの状態を更新していきます。
ラインナンバープログラムのヘッダには、いくつかの重要な情報が含まれています。その一つがopcode_base
です。この値は、特別なオペコードが始まるオフセットを示します。DWARF 2仕様では、9つの標準オペコードが定義されています。これらの標準オペコードは、通常、1から9までの値にマッピングされます。したがって、dwarfdump
のようなツールがこれらの9つの標準オペコードを正しく認識するためには、opcode_base
が少なくとも10である必要があります(1から9までの標準オペコードの後に特別なオペコードが続くため)。
Goリンカは以前、OPCODE_BASE
を5と定義していました。これは、標準オペコードが1から4までしか利用できないことを意味し、DWARF 2仕様で定義されている残りの標準オペコード(5から9)が正しく解釈されない可能性がありました。この不整合が、dwarfdump
がGoが生成したDWARF情報に対して警告を発したり、一部の情報を正しく表示できなかったりする原因となっていました。
このコミットでは、OPCODE_BASE
を10に変更することで、DWARF 2仕様の9つの標準オペコードすべてが正しく認識されるようになります。これにより、Goリンカが生成するDWARF情報が、dwarfdump
を含む他のDWARFツールとの互換性が向上します。
また、writelines
関数内でstandard_opcode_lengths
配列の初期化も変更されています。OPCODE_BASE
が10になったことで、配列のサイズが拡張され、標準オペコード5から9に対応するエントリが追加されています。これにより、各標準オペコードが取るオペランドの数が正しく設定され、ラインナンバープログラムの解釈がより正確になります。
コアとなるコードの変更箇所
変更は src/cmd/ld/dwarf.c
ファイルに集中しています。
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -1412,7 +1412,7 @@ finddebugruntimepath(LSym *s)
enum {
LINE_BASE = -1,
LINE_RANGE = 4,
- OPCODE_BASE = 5
+ OPCODE_BASE = 10
};
static void
@@ -1541,11 +1541,16 @@ writelines(void)
cput(1); // default_is_stmt
cput(LINE_BASE); // line_base
cput(LINE_RANGE); // line_range
- cput(OPCODE_BASE); // opcode_base (we only use 1..4)
+ cput(OPCODE_BASE); // opcode_base
cput(0); // standard_opcode_lengths[1]
cput(1); // standard_opcode_lengths[2]
cput(1); // standard_opcode_lengths[3]
cput(1); // standard_opcode_lengths[4]
+ cput(1); // standard_opcode_lengths[5]
+ cput(0); // standard_opcode_lengths[6]
+ cput(0); // standard_opcode_lengths[7]
+ cput(0); // standard_opcode_lengths[8]
+ cput(1); // standard_opcode_lengths[9]
cput(0); // include_directories (empty)
files = emallocz(ctxt->nhistfile*sizeof files[0]);
コアとなるコードの解説
-
OPCODE_BASE
の変更:enum
定義内で、OPCODE_BASE
の値が5
から10
に変更されています。- OPCODE_BASE = 5 + OPCODE_BASE = 10
これは、DWARFラインナンバープログラムのヘッダに書き込まれるオペコードベースの値を直接変更するものです。これにより、特別なオペコードが始まるオフセットが調整され、DWARF 2仕様で定義されている9つの標準オペコード(1から9)がすべて、標準オペコードとして正しく認識されるようになります。
-
standard_opcode_lengths
の初期化の拡張:writelines
関数内で、standard_opcode_lengths
配列の初期化部分が変更されています。以前は標準オペコード1から4までの長さしか記述されていませんでしたが、OPCODE_BASE
が10になったことに伴い、標準オペコード5から9までの長さも追加で記述されるようになりました。cput(1); // standard_opcode_lengths[1] cput(1); // standard_opcode_lengths[2] cput(1); // standard_opcode_lengths[3] cput(1); // standard_opcode_lengths[4] + cput(1); // standard_opcode_lengths[5] + cput(0); // standard_opcode_lengths[6] + cput(0); // standard_opcode_lengths[7] + cput(0); // standard_opcode_lengths[8] + cput(1); // standard_opcode_lengths[9]
standard_opcode_lengths
は、各標準オペコードが取るオペランドの数を定義する配列です。この変更により、Goリンカが生成するDWARFラインナンバープログラムのヘッダが、DWARF 2仕様に完全に準拠し、他のDWARFツールがより正確にデバッグ情報を解析できるようになります。特に、standard_opcode_lengths[5]
とstandard_opcode_lengths[9]
が1に設定されていることから、これらのオペコードが1つのオペランドを取ることが示唆されます。他のオペコード(6, 7, 8)が0に設定されているのは、それらがオペランドを取らないか、Goのコンテキストでは使用されないことを意味する可能性があります。
関連リンク
- Go issue/discussion: https://groups.google.com/forum/#!topic/golang-dev/d-BqpPgalzc
- Go CL (Change List): https://golang.org/cl/69320043
参考にした情報源リンク
- DWARF 2 Specification: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQENjoOv31J71XZK53xWhsNSIrEFjT7feEaN3f5K8GmC8Q4Zqygxo77u5684glM8GsIXMl8ZEkbaVxkbbaoi5cltDAS3jLbAfTPNHrXyHA2vMhgelmql2pE= (osdev.org)
dwarfdump
utility: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF-EBHtWDSzc8CF6iiDEkFNdaPpH36CpD1mx4sHWAGMB9gJsbsJgH3IspvmKlSMRm4gctFz3X1RC4Hk2sxncM5GJdouHg3xJaTbs2Nnv_YqGKF9LIuvwvW2xsx07iaE5SlEh1A7LkFqcyRvA-svQWUOKiqtqXfu26Uijkg= (ubuntu.com)- Go DWARF information: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH0okFaf5apy3KZXDMfaA8AW2KUdTrqNOH8G8i2zF2J90pDtg6T7l7l4UF4cXwXzAIrYnj_WuMXpXpozHJXalbmUcV71mMRAq_5YDFhymrDvIpfhuCAtPh40QOJ52wmWr5sWsozG40KidTMHt-q (uber.com)