シグナル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_code
0x80の値を取得せず、「アドレスがオブジェクトにマップされていない」を意味する0x1の値を取得します。
答え1
si_code = SI_KERNEL
文書化されていないwithの意味はsi_errno = 0
次のとおりです。
- プロセッサ別トラップ
- カーネルセグメントメモリ違反(セマフォアクセスを除く)
- ELFファイル形式違反
- スタック違反。
他のすべてはゼロ以外の値に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 setrlimit
in 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
カーネルログを設定して確認することで、より多くの情報を取得できます。