[インデックス 13071] ファイルの概要
このコミットは、Go言語のランタイムにおけるNetBSDオペレーティングシステム上でのシグナルハンドリングの修正を目的としています。具体的には、NetBSDのシグナルコンテキスト構造体(sigcontext
、ucontext_t
、mcontext_t
)およびシグナル情報構造体(siginfo_t
)の定義がGoランタイム内で正しく反映されるように、レジスタへのアクセス方法やシグナル情報の取得方法を更新しています。これにより、NetBSD環境でのGoプログラムのクラッシュハンドリングやプロファイリングが正確に行われるようになります。
コミット
commit 4a5a5b20a53493fc3c3803cb2099e38677a5d83f
Author: Joel Sing <jsing@google.com>
Date: Wed May 16 01:53:26 2012 +1000
runtime: fix netbsd signal handling
Update/correct NetBSD signal handling - most of this is needed due to
the correctly generated runtime definitions.
R=golang-dev, m4dh4tt3r, rsc
CC=golang-dev
https://golang.org/cl/6195079
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4a5a5b20a53493fc3c3803cb2099e38677a5d83f
元コミット内容
runtime: fix netbsd signal handling
Update/correct NetBSD signal handling - most of this is needed due to
the correctly generated runtime definitions.
R=golang-dev, m4dh4tt3r, rsc
CC=golang-dev
https://golang.org/cl/6195079
変更の背景
この変更の背景には、GoランタイムがNetBSDのシステムコールやデータ構造と正確に連携する必要があるという根本的な要件があります。Goランタイムは、OSレベルのシグナルを捕捉し、それらをGoのランタイムパニックやプロファイリングイベントに変換する役割を担っています。
コミットメッセージにある「correctly generated runtime definitions」という記述は、Goのビルドプロセスにおいて、NetBSDのシステムヘッダファイルからGoランタイムが使用するCgo定義(またはそれに類する低レベルのインターフェース定義)が生成される際に、何らかの変更があったことを示唆しています。これは、NetBSD自体のカーネルやlibcのAPI定義が更新されたか、あるいはGoのツールチェインがこれらの定義を解釈する方法が改善された結果であると考えられます。
具体的には、NetBSDのシグナルハンドリングに関連する構造体、特にsigcontext
、ucontext_t
、mcontext_t
、siginfo_t
の内部構造やフィールド名が変更された可能性があります。GoランタイムはこれらのOS固有の構造体に直接アクセスしてレジスタの状態やシグナルの詳細情報を取得するため、OS側の定義変更に追従する必要がありました。このコミットは、これらの「正しい」定義に合わせてGoランタイムのコードを更新し、シグナルハンドリングの正確性と堅牢性を確保することを目的としています。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
Unixシグナル:
- Unix系OSにおけるプロセス間通信やイベント通知のメカニズム。
SIGSEGV
(セグメンテーション違反)、SIGFPE
(浮動小数点例外)、SIGILL
(不正命令) など、プログラムの異常終了を引き起こすシグナルや、SIGPROF
(プロファイリングタイマー) のように特定の目的で使用されるシグナルがあります。- シグナルが発生すると、OSは通常、プロセスに登録されたシグナルハンドラを呼び出します。
-
シグナルハンドラ:
- 特定のシグナルが発生した際にOSによって呼び出される関数。
- シグナルハンドラは、シグナル番号、シグナル情報(
siginfo_t
)、およびコンテキスト情報(ucontext_t
)を受け取ります。
-
siginfo_t
構造体:- シグナルに関する詳細情報を提供する構造体。
si_code
フィールドはシグナルの発生原因(例:SI_USER
はkill()
による送信、SEGV_MAPERR
は無効なアドレスへのアクセス)を示します。si_addr
フィールドは、SIGSEGV
などのメモリ関連のシグナルで、エラーが発生したメモリアドレスを示します。- NetBSDでは、これらのフィールドが内部的に異なる名前(例:
_code
,_reason
)で定義されている場合があります。
-
コンテキスト構造体 (
ucontext_t
,mcontext_t
,sigcontext
):- シグナル発生時のプロセスの実行コンテキスト(CPUレジスタの状態、スタックポインタ、プログラムカウンタなど)を保存する構造体。
ucontext_t
はユーザーコンテキスト全体を表し、その中にmcontext_t
(マシンコンテキスト、つまりCPUレジスタの状態)が含まれるのが一般的です。sigcontext
は古いシステムや特定のアーキテクチャで使われる、よりシンプルなコンテキスト構造体です。- Goランタイムは、これらの構造体からプログラムカウンタ(
EIP
/RIP
)やスタックポインタ(ESP
/RSP
)などのレジスタ値を取得し、スタックトレースの生成やパニック処理に利用します。
-
Goランタイムのシグナルハンドリング:
- Goは独自のシグナルハンドラを登録し、OSからのシグナルを捕捉します。
SIGSEGV
などの致命的なシグナルはGoのパニックに変換され、スタックトレースが出力されます。SIGPROF
はプロファイリングのために使用され、定期的にプログラムの実行状態をサンプリングします。runtime·sigpanic
: Goランタイムがシグナルによってパニックを処理する際に呼び出される内部関数。runtime·dumpregs
: シグナル発生時のレジスタ状態をダンプする関数。デバッグに役立ちます。runtime·traceback
: スタックトレースを生成する関数。
技術的詳細
このコミットの主要な技術的変更点は、NetBSDのシグナルハンドリングにおけるコンテキスト構造体とシグナル情報構造体へのアクセス方法の変更です。
-
Sigcontext
からUcontextT
/McontextT
への移行:- 変更前は、シグナルハンドラの
context
引数を直接Sigcontext *r
としてキャストし、レジスタにアクセスしていました。 - 変更後は、
context
引数をUcontextT *uc
として受け取り、その中のuc->uc_mcontext
をMcontextT *mc
として抽出しています。これは、NetBSDがシグナルハンドラに渡すコンテキストが、より標準的なucontext_t
構造体であり、その中にマシン固有のレジスタ情報がmcontext_t
として含まれていることを反映しています。 runtime·dumpregs
関数も、引数をSigcontext *r
からMcontextT *mc
に変更し、直接mcontext_t
からレジスタ情報を取得するように修正されています。
- 変更前は、シグナルハンドラの
-
レジスタアクセス方法の変更:
- 変更前は、
r->sc_eax
(386) やr->sc_rax
(amd64) のように、Sigcontext
構造体の直接のフィールドとしてレジスタにアクセスしていました。 - 変更後は、
mc->__gregs[REG_EAX]
(386) やmc->__gregs[REG_RAX]
(amd64) のように、McontextT
構造体内の__gregs
配列を介してレジスタにアクセスしています。これは、NetBSDのmcontext_t
がレジスタを配列として保持する形式に変わったか、あるいはGoランタイムがその形式をより正確に解釈するようになったことを示しています。REG_EAX
などのマクロは、配列内の特定のレジスタのインデックスを定義しています。
- 変更前は、
-
siginfo_t
フィールドへのアクセス変更:runtime·sighandler
関数内で、siginfo_t
構造体のフィールドへのアクセス方法が変更されています。info->si_code
がinfo->_code
に変更されました。si_addr
(エラー発生アドレス)の取得方法が、*(uintptr*)((byte*)info + 12)
(386) や*(uintptr*)((byte*)info + 16)
(amd64) といったオフセット指定から、*(uintptr*)&info->_reason[0]
に変更されました。これは、siginfo_t
構造体内部でのsi_code
やsi_addr
の定義が、NetBSDの特定のバージョンで変更されたか、あるいはGoランタイムがよりポータブルな方法でこれらのフィールドにアクセスするように調整されたことを示唆しています。_reason
は、シグナルの原因に関する追加情報を含む共用体(union)または配列である可能性が高いです。
-
runtime·signalstack
の型キャスト削除:st.ss_sp = (int8*)p;
からst.ss_sp = p;
へと変更されています。これは、Sigaltstack
構造体のss_sp
フィールドの型がbyte *
(またはそれに相当するポインタ型)に更新され、不要な型キャストが削除されたことを意味します。これにより、コードの可読性と型安全性が向上します。
これらの変更は、GoランタイムがNetBSDの低レベルなシグナルハンドリングAPIとより正確に同期し、OSの進化に追従するための重要な更新です。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルと関数は以下の通りです。
-
src/pkg/runtime/signal_netbsd_386.c
:runtime·dumpregs
関数の引数とレジスタアクセスruntime·sighandler
関数のコンテキスト取得、siginfo_t
フィールドアクセス、レジスタアクセスruntime·signalstack
関数の型キャスト
-
src/pkg/runtime/signal_netbsd_amd64.c
:runtime·dumpregs
関数の引数とレジスタアクセスruntime·sighandler
関数のコンテキスト取得、siginfo_t
フィールドアクセス、レジスタアクセスruntime·signalstack
関数の型キャスト
-
src/pkg/runtime/signals_netbsd.h
:runtime·sigtab
配列のコメントのフォーマット変更(機能的な変更なし)
コアとなるコードの解説
runtime·dumpregs
関数
この関数は、シグナル発生時のCPUレジスタの状態を標準出力にダンプします。デバッグやクラッシュレポートの際に非常に重要です。
変更前はSigcontext
ポインタを受け取っていましたが、変更後はMcontextT
ポインタを受け取るようになりました。これにより、NetBSDの新しいコンテキスト構造体から直接レジスタ値を取得できるようになりました。レジスタへのアクセスも、r->sc_eax
のような直接的なフィールドアクセスから、mc->__gregs[REG_EAX]
のような配列インデックスによるアクセスに変わっています。これは、NetBSDのmcontext_t
構造体におけるレジスタの格納方法が、個別のフィールドではなく配列として統一されたことを示唆しています。
runtime·sighandler
関数
Goランタイムのシグナルハンドラの中心となる関数です。OSからシグナルが配送されると、この関数が呼び出されます。
最も重要な変更は、context
引数の解釈です。以前はSigcontext *r
として扱っていましたが、NetBSDのシステム定義に合わせてUcontextT *uc
として受け取り、その中のuc->uc_mcontext
からMcontextT *mc
を抽出するように変更されました。これにより、GoランタイムはNetBSDが提供する完全なユーザーコンテキスト情報にアクセスできるようになります。
また、siginfo_t
構造体からの情報取得も変更されました。
info->si_code
がinfo->_code
に変更されたのは、siginfo_t
内部でのシグナルコードのフィールド名が変更されたためです。si_addr
(シグナルが発生したアドレス)の取得方法が、ハードコードされたオフセット計算から*(uintptr*)&info->_reason[0]
に変更されました。これは、siginfo_t
のsi_addr
フィールドが、_reason
という共用体(union)の一部として定義されるようになったためと考えられます。この変更により、GoランタイムはNetBSDのsiginfo_t
の最新の定義に準拠し、正確なエラーアドレスを取得できるようになります。
これらの変更は、SIGPROF
によるプロファイリング時のプログラムカウンタ(EIP
/RIP
)とスタックポインタ(ESP
/RSP
)の取得、およびSigPanic
(Goのパニック)発生時のプログラムカウンタとスタックポインタの操作に影響を与えます。これにより、NetBSD上でのGoプログラムのプロファイリングとクラッシュレポートがより正確になります。
runtime·signalstack
関数
この関数は、シグナルハンドラが実行される代替スタックを設定します。
st.ss_sp = (int8*)p;
から st.ss_sp = p;
への変更は、Sigaltstack
構造体のss_sp
フィールドの型が、byte *
(またはそれに相当するポインタ型)に更新されたことを示しています。これにより、不要な型キャストが削除され、コードがよりクリーンになりました。
関連リンク
- Go Change-Id:
I2222222222222222222222222222222222222222
(これはコミットメッセージに記載されているhttps://golang.org/cl/6195079
に対応するGoの内部的な変更リストIDです。通常、GitHubのコミットページから直接参照できます。)
参考にした情報源リンク
- NetBSDのシグナルハンドリングに関する公式ドキュメント (具体的なバージョンや時期によって異なるため、一般的な情報源を記載)
sigaction(2)
man page (NetBSD): シグナルハンドラの登録と動作についてsiginfo(2)
man page (NetBSD):siginfo_t
構造体の詳細についてgetcontext(2)
/setcontext(2)
man page (NetBSD):ucontext_t
構造体の詳細について
- Go言語のランタイムに関するドキュメントやソースコード (Goの公式ドキュメントやGoのソースコードリポジトリ)
- Goの
syscall
パッケージのドキュメント - Goの
runtime
パッケージのソースコード
- Goの
- Unix/Linuxプログラミングに関する一般的な書籍やオンラインリソース (シグナル、コンテキスト、システムコールについて)
- The Linux Programming Interface (TLPI) など
- (もしWeb検索で具体的なNetBSDの変更履歴が見つかれば、そのリンクをここに追記します。)
- 例: NetBSDの特定のバージョンにおける
ucontext_t
やsiginfo_t
の変更に関するリリースノートや開発者メーリングリストのアーカイブ。
- 例: NetBSDの特定のバージョンにおける