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

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

このコミットは、Go言語のランタイムにおけるNetBSDオペレーティングシステム上でのシグナルハンドリングの修正を目的としています。具体的には、NetBSDのシグナルコンテキスト構造体(sigcontextucontext_tmcontext_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のシグナルハンドリングに関連する構造体、特にsigcontextucontext_tmcontext_tsiginfo_tの内部構造やフィールド名が変更された可能性があります。GoランタイムはこれらのOS固有の構造体に直接アクセスしてレジスタの状態やシグナルの詳細情報を取得するため、OS側の定義変更に追従する必要がありました。このコミットは、これらの「正しい」定義に合わせてGoランタイムのコードを更新し、シグナルハンドリングの正確性と堅牢性を確保することを目的としています。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  1. Unixシグナル:

    • Unix系OSにおけるプロセス間通信やイベント通知のメカニズム。
    • SIGSEGV (セグメンテーション違反)、SIGFPE (浮動小数点例外)、SIGILL (不正命令) など、プログラムの異常終了を引き起こすシグナルや、SIGPROF (プロファイリングタイマー) のように特定の目的で使用されるシグナルがあります。
    • シグナルが発生すると、OSは通常、プロセスに登録されたシグナルハンドラを呼び出します。
  2. シグナルハンドラ:

    • 特定のシグナルが発生した際にOSによって呼び出される関数。
    • シグナルハンドラは、シグナル番号、シグナル情報(siginfo_t)、およびコンテキスト情報(ucontext_t)を受け取ります。
  3. siginfo_t構造体:

    • シグナルに関する詳細情報を提供する構造体。
    • si_codeフィールドはシグナルの発生原因(例: SI_USERkill()による送信、SEGV_MAPERRは無効なアドレスへのアクセス)を示します。
    • si_addrフィールドは、SIGSEGVなどのメモリ関連のシグナルで、エラーが発生したメモリアドレスを示します。
    • NetBSDでは、これらのフィールドが内部的に異なる名前(例: _code, _reason)で定義されている場合があります。
  4. コンテキスト構造体 (ucontext_t, mcontext_t, sigcontext):

    • シグナル発生時のプロセスの実行コンテキスト(CPUレジスタの状態、スタックポインタ、プログラムカウンタなど)を保存する構造体。
    • ucontext_tはユーザーコンテキスト全体を表し、その中にmcontext_t(マシンコンテキスト、つまりCPUレジスタの状態)が含まれるのが一般的です。
    • sigcontextは古いシステムや特定のアーキテクチャで使われる、よりシンプルなコンテキスト構造体です。
    • Goランタイムは、これらの構造体からプログラムカウンタ(EIP/RIP)やスタックポインタ(ESP/RSP)などのレジスタ値を取得し、スタックトレースの生成やパニック処理に利用します。
  5. Goランタイムのシグナルハンドリング:

    • Goは独自のシグナルハンドラを登録し、OSからのシグナルを捕捉します。
    • SIGSEGVなどの致命的なシグナルはGoのパニックに変換され、スタックトレースが出力されます。
    • SIGPROFはプロファイリングのために使用され、定期的にプログラムの実行状態をサンプリングします。
    • runtime·sigpanic: Goランタイムがシグナルによってパニックを処理する際に呼び出される内部関数。
    • runtime·dumpregs: シグナル発生時のレジスタ状態をダンプする関数。デバッグに役立ちます。
    • runtime·traceback: スタックトレースを生成する関数。

技術的詳細

このコミットの主要な技術的変更点は、NetBSDのシグナルハンドリングにおけるコンテキスト構造体とシグナル情報構造体へのアクセス方法の変更です。

  1. SigcontextからUcontextT/McontextTへの移行:

    • 変更前は、シグナルハンドラのcontext引数を直接Sigcontext *rとしてキャストし、レジスタにアクセスしていました。
    • 変更後は、context引数をUcontextT *ucとして受け取り、その中のuc->uc_mcontextMcontextT *mcとして抽出しています。これは、NetBSDがシグナルハンドラに渡すコンテキストが、より標準的なucontext_t構造体であり、その中にマシン固有のレジスタ情報がmcontext_tとして含まれていることを反映しています。
    • runtime·dumpregs関数も、引数をSigcontext *rからMcontextT *mcに変更し、直接mcontext_tからレジスタ情報を取得するように修正されています。
  2. レジスタアクセス方法の変更:

    • 変更前は、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などのマクロは、配列内の特定のレジスタのインデックスを定義しています。
  3. siginfo_tフィールドへのアクセス変更:

    • runtime·sighandler関数内で、siginfo_t構造体のフィールドへのアクセス方法が変更されています。
    • info->si_codeinfo->_codeに変更されました。
    • si_addr(エラー発生アドレス)の取得方法が、*(uintptr*)((byte*)info + 12) (386) や *(uintptr*)((byte*)info + 16) (amd64) といったオフセット指定から、*(uintptr*)&info->_reason[0]に変更されました。これは、siginfo_t構造体内部でのsi_codesi_addrの定義が、NetBSDの特定のバージョンで変更されたか、あるいはGoランタイムがよりポータブルな方法でこれらのフィールドにアクセスするように調整されたことを示唆しています。_reasonは、シグナルの原因に関する追加情報を含む共用体(union)または配列である可能性が高いです。
  4. 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_codeinfo->_codeに変更されたのは、siginfo_t内部でのシグナルコードのフィールド名が変更されたためです。
  • si_addr(シグナルが発生したアドレス)の取得方法が、ハードコードされたオフセット計算から*(uintptr*)&info->_reason[0]に変更されました。これは、siginfo_tsi_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パッケージのソースコード
  • Unix/Linuxプログラミングに関する一般的な書籍やオンラインリソース (シグナル、コンテキスト、システムコールについて)
    • The Linux Programming Interface (TLPI) など
  • (もしWeb検索で具体的なNetBSDの変更履歴が見つかれば、そのリンクをここに追記します。)
    • 例: NetBSDの特定のバージョンにおけるucontext_tsiginfo_tの変更に関するリリースノートや開発者メーリングリストのアーカイブ。