sigaction(7): siginfo_t の si_code メンバーの意味体系

sigaction(7): siginfo_t の si_code メンバーの意味体系

シグナル11(セグメント違反)で頻繁に終了する長期実行プログラム(daemon(3)呼び出しを介してデーモン化)があります。理由はわかりません。したがって、sigaction()システムコールを使用して設定するSIGSEGVハンドラを作成しました。次のプロトタイプを持つようにハンドラ関数を設定しました。これは、型パラメータで構造へのポインタをvoid (*sa_sigaction)(int, siginfo_t *, void *)取得することを意味します。siginfo_t

不思議なSIGSEGVが発生すると、si_code要素siginfo_t値は0x80です。 sigactionのマニュアルページによると、これは「カーネル」がシグナルを送ったことを意味します。これはRed Hat RHELシステムにあります。Linux blahblah 2.6.18-308.20.1.el5 #1 SMP Tue Nov 6 04:38:29 EST 2012 x86_64 x86_64 x86_64 GNU/Linux

カーネルがSIGSEGVを送信するのはなぜですか?これは有名なOOM-Killerからのものですか、それともSIGSEGVを得る他の理由がありますか?このシステムの一般ユーザーとして、私はそれを見ることができず、/var/log/messageシステム管理者はおそらくWindowsの背景から来たので少し冷ややかです。

意図的に生成されたSIGSEGV(NULLポインタ逆参照)は、si_code0x80の値を取得せず、「アドレスがオブジェクトにマップされていない」を意味する0x1の値を取得します。

ベストアンサー1

si_code = SI_KERNEL文書化されていないwithの意味はsi_errno = 0次のとおりです。

  1. プロセッサ別トラップ
  2. カーネルセグメントメモリ違反(セマフォアクセスを除く)
  3. ELFファイル形式違反
  4. スタック違反。

他のすべてはゼロ以外の値にSIGSEGV設定する必要があります。si_errno詳細については、読んでください。

カーネルは、ユーザー空間プロセスを設定するときにプロセスの仮想メモリページテーブルを定義します。カーネルスケジューラは、プロセスを実行すると、プロセスのページテーブルに基づいてCPUのメモリ管理デバイス(MMU)を再設定します。

ユーザー空間プロセスがページテーブルの外側のメモリにアクセスしようとすると、CPU MMUはこの違反を検出して例外を生成します。これが起こりますので、ハードウェア評価。カーネルはまだ扱われていません。

カーネルは、MMU 例外を処理するように構成されています。ページテーブルの外部のメモリにアクセスしようとしている実行中のプロセスによって発生した例外をキャッチします。その後、カーネルはdo_page_fault()それを呼び出してSIGSEGV信号をプロセスに送信します。これが、信号がプロセス自体や他のプロセスから来るのではなく、カーネルから出てくる理由です。

もちろん、これは非常に単純化された説明です。私が見た最も簡単な説明は、William Gatliffの素晴らしい記事の「ページエラー」セクションにあります。Linuxカーネルメモリ管理デバイスAPI

Blackfin MPUなど、MMUを持たないCPUでは、Linuxユーザースペースプロセスが通常アクセスできます。どのメモリ。つまり、メモリ違反に対するSIGSEGV信号がなく(スタックオーバーフローなどのトラップのみ)、メモリアクセスの問題をデバッグするのは難しいかもしれません。

私はulimitコアファイルを設定して確認することに関するjordanmのコメントに同意しますgdb。シェルでプロセスを実行している場合は、コマンドラインから操作を実行するか、ulimit -c unlimitedプログラムでlibcsetrlimitシステムコールラッパー()を使用できます。man setrlimitin fileでコアファイルの名前と場所を設定できます/proc/sys/kernel/core_pattern。これについてはAP Lawrenceの素晴らしい説明を参照してください。制御コアファイル(Linux)。コアファイルで使用するには、gdbこの小さなコンテンツを参照してください。地図時間steve.orgから

SEGV_MAPERR(0x1)の分割違反は、NULLポインタの逆参照、si_code存在しないメモリ(0xfffffc0000004000など)のアクセス、またはmallocその他のfree問題です。man getrlimitヒープが破損しているか、プロセスがランタイム制限を超える場合、二重malloc解放または未割り当てアドレス解放の場合free。その他の手がかりについては、この要素を確認してくださいsi_errno

TASK_SIZE制限を超える仮想メモリにアクセスするユーザースペースプロセスによって引き起こされる分割違反が原因で、分割si_code違反が発生しますSI_KERNEL。つまり、TASK_SIZE制限は、すべてのプロセスがアクセスできる最も高い仮想アドレスです。カーネルが高メモリサポート用に設定されていない場合、通常は3GBです。制限の上の領域をTASK_SIZE「カーネルセグメント」と呼びます。linux-2.6//arch/x86/mm/fault.c:__bad_area_nosemaphore(...)それがどこにあるか見てくださいforce_sig_info_fault(...)

各アーキテクチャには、SIEGVにつながるいくつかの特定のトラップがありますSI_KERNEL。 x86の場合linux-2.6//arch/x86/kernel/traps.c

linux-2.6//mm/oom_kill.c:oom_kill_process(...)OOM ハンドラは、関数の行 498 の周囲に示すように、SIGSEGV の代わりに SIGKILL を送信します。

do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);

関連プロセスおよびライン503の場合:

do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);

このプロセスはOOMの最も直接的な原因です。

wait親プロセスで終了したプロセスの状態を確認するか、dmesgカーネルログを設定して確認することで、より多くの情報を取得できます。

おすすめ記事