FreeBSD 2.X についての FAQ (よくある質問とその答え) : まじめな FreeBSD ハッカーだけの話題 : カーネルパニックを最大限に利用する
Previous: 代替のディレクトリ配置ポリシー
Next: 謝辞

13.13. カーネルパニックを最大限に利用する

[この節は, freebsd-current mailing listBill Paul が投稿したメールを, Dag-Erling Coïdan Smørgrav が校正し,括弧内のコ メントを追加して引用したものです. ]

From: Bill Paul <wpaul@skynet.ctr.columbia.edu>
Subject: Re: the fs fun never stops
To: ben@rosengart.com
Date: Sun, 20 Sep 1998 15:22:50 -0400 (EDT)
Cc: current@FreeBSD.ORG
      

[<ben@rosengart.com> が以下のパニックメッセージを 投稿しました.]

> Fatal trap 12: page fault while in kernel mode
> fault virtual address   = 0x40
> fault code              = supervisor read, page not present
> instruction pointer     = 0x8:0xf014a7e5
                                ^^^^^^^^^^
> stack pointer           = 0x10:0xf4ed6f24
> frame pointer           = 0x10:0xf4ed6f28
> code segment            = base 0x0, limit 0xfffff, type 0x1b
>                         = DPL 0, pres 1, def32 1, gran 1
> processor eflags        = interrupt enabled, resume, IOPL = 0
> current process         = 80 (mount)
> interrupt mask          =
> trap number             = 12
> panic: page fault
      

このようなメッセージが表示された場合, 問題が起きる状況を確認し て, 情報を送るだけでは十分ではありません. 下線をつけた命令ポインタ 値は重要な値ですが, 残念ながらこの値は構成に依存します. つまり, こ の値は使っているカーネルのイメージに依存するのです. もしスナップショッ トなどの GENERIC カーネルを使っているのであれば, 他の人間が問題の ある関数について追試をすることができますが, カスタマイズされたカー ネルの場合は, 使っている本人にしか問題の起こった場所は特定できない のです.

何をすれば良いのでしょう?

このようなパニックメッセージを投稿している人はよく見掛けますが, このように, 命令ポインタ値を, カーネルシンボルテーブルの中の関数 とつき合わせて調べている人はまれです.

パニックの原因を突き止める最良の方法は, クラッシュダンプをとり, gdb(1) でスタックトレースを行うことです. もちろん -current で gdb(1) がちゃんと動いていればですが (私は動くことを保証 できません. ELF 化された gdb(1) はカーネルクラッシュダンプを 正しく扱えないと言っている人がいました. 3.0 がβテストを終える前, に調べなければいけません. さもないと CD 出荷後に大顰蹙を買うことに なります).

どっちにしろ, 私は普通以下のようにします.

[注: 現在 FreeBSD 3.x kernel はデフォルトで ELF 形式となっており, strip -d の代りに strip -g を使う必要があります. 何らかの理由でまだ a.out 形式の kernel を使っている場合は, strip -aout -d を使ってください. ]

全てのデバッグシンボルを含んだカーネルを, 実際にブートする必要は ありません. -g をつけてコンパイルされたカーネルは, 簡単に 10MB 近くの大きさになってしまいます. こんな大きなカーネル を実際にブートする必要はありません. この大きなカーネルイメージは 後でgdb(1)を使うときにのみ必要です(gdb(1) がシンボル テーブルを必要とするため). シンボルを含んだカーネルのコピーを保 存 しておき, strip -d を使ってシンボルを除いたカーネルを作 成して ブートします.

確実にクラッシュダンプをとるには, /etc/rc.conf を編 集して dumpdev を使用しているスワップパーティションに指定す る必 要があります. こうすると rc(8) スクリプトから dumpon(8) コマンドが実行されクラッシュダンプ機能が有効にな ります. 手動で dumpon(8) コマンドを実行してもかまいませ ん. パニックの後, クラッシュダンプは savecore(8) コマンドを 使用して取り出すこと ができます. dumpdev/etc/rc.conf で設定されていれ ば, rc(8) スクリプト から savecore(8) が自動的に実行され, クラッシュダンプを /var/crash に保存します.

注: FreeBSD のクラッシュダンプのサイズは, ふつう物理メモリサ イズと同じです. つまり 64MB のメモリを積んでいれば, 64MB のクラッ シュ ダンプが生成されることになります. /var/crash に十 分な空き 容量があることを確認してください. 手動で savecore(8) を実行す れば, もっと空き容量のあるディレクトリ にクラッシュダンプを保存でき ます. options MAXMEM=(foo) と いう行をカーネルコンフィグファイ ルに追加することで, カーネルの メモリ使用量を制限できます. たとえば 128MB のメモリがある場合も, カーネルのメモリ使用量を 16MB に制限し クラッシュダンプのサイズ も 128MB ではなく 16MB にすることができます.

クラッシュダンプを取り出せたら, 以下のように gdb(1) を使っ てスタックトレースをとります:

% gdb -k /sys/compile/KERNELCONFIG/kernel.debug /var/crash/vmcore.0
(gdb) where
      

必要な情報が 1 画面に収まらないことも多いので, できれば script(1) を使って出力を記録します. strip していないカーネ ル イメージを使うことで, 全てのデバッグシンボルが参照でき, パニッ ク の発生したカーネルのソースコードの行が表示されているはずです. 通常, 正確なクラッシュへの過程を追跡するには, 出力を最後の行から 逆方向に読まなければなりません. また gdb(1) を使って, 変数 や 構造体の内容を表示させ, クラッシュした時のシステムの状態を調 べられ ます.

もしあなたがデバッグ狂で, 同時に別のコンピュータを利用できる 環境にあれば, gdb(1) をリモートデバッグに使うこともできます. リモートデバッグを使うと, あるコンピュータ上の gdb(1) を使っ て, 別のコンピュータのカーネルをデバッグできます. ブレークポイン トの設 定, カーネルコードのステップ実行など, ふつうのプログラム のデバッグ と変わりません. コンピュータを 2 台並べてデバッグする チャンスには, なかなか恵まれないので, 私はまだリモートデバッグを 試したことはあり ません.

[Bill による注: DDB を有効にしていてカーネルがデバッガに 落ちたら, ddb のプロンプトで 'panic' と入力すれば, 強制的にパニッ クを 起こしクラッシュダンプさせることができます. パニックの途中 で, 再び デバッガに落ちるかもしれませんが, 'continue' と入力すれ ば, クラッシュダンプを最後まで実行させられます.]


FreeBSD 2.X についての FAQ (よくある質問とその答え) : まじめな FreeBSD ハッカーだけの話題 : カーネルパニックを最大限に利用する
Previous: 代替のディレクトリ配置ポリシー
Next: 謝辞