DDBを使ったオンラインカーネルデバッグ

kgdb は非常に高レベルのユーザインタフェースを提 供するオフラインデバッガですが, いくつかのことはできません. (できないことの中で) 極めて重要なことはカーネルコードへのブレークポイ ントの設定とシングルステップ実行です.

カーネルの低レベルデバッグが必要であれば, DDBと呼ばれる on-lineデバッ ガが使えます. ブレークポイントの設定, シングルステップのカーネルの実 行, 変数の検査と変更などができます. ただし,これはカーネルのソースファ イルにアクセスすることはできません. kgdbのようにすべてのデ バッグ情報にはアクセスできず, globalと staticのシンボルにアクセス することができるだけです.

カーネルに DDB を含めるためにはコンフィグファイルに次のようなオプショ ンを加えて,

options DDB

再構築をおこないます. ( FreeBSDのカーネルの設定の詳細については FreeBSD カーネルのコンフィグレーションを参照してくださ い.

Note: もしブートブロックが古いバージョンですと, デバッガのシンボルが完 全にはロードされないかもしれませんので注意してください. DDB シンボル がロードされるようにブートブロックを 最新の物にアップデートしてくださ い)

DDB カーネルの実行において, DDBに入るいくつかの方法があります. 最初 の, 最も早い方法はブートプロンプトが出ている時に -dのブート フラグをタイプすることです. カーネルはデバッグモードで起動し, デバ イスのプローブ以前に DDBに入ります. したがって, デバイスのプローブ/初期 設定ファンクションのデバッグができます.

2つ目のシナリオはキーボードのホットキーで, 通常は Ctrl-Alt-ESCです. syscons ではホットキーは再設定することができ, 配付されているいくつかの キーマッピングでは別のキーに 再設定されていますので確認しておいてください. シリアルラインの BREAKを使って シリアルコンソールから DDBへ入ることを可 能にするオプションもあります (カーネルコンフィグレーションファイルの options BREAK_TO_DEBUGGER). これは 多くのつまらないシリ アルアダプタが, 例えばケーブルを引き抜いた時に BREAK状態を意味もなく 作り出してしまうのでデフォルトでは無効になっています.

3つ目は, DDB を使うようになっているカーネルがパニック状態になると DDB へ入るというものです. このため, 無人運転するマシンのカーネルにDDBを 入れるのは賢明ではありません.

DDB のコマンドはおおまかには gdb のいくつかのコマンドと似て います. おそらく最初にブレークポイントを 設定する必要があるでしょう.

b function-name
b address

数値はデフォルトでは16進数で, シンボル名とはまったく異ります. 16進数で a-f の文字で始まる場合は, 先頭に 0x をつける必要があります(それ以外の数字の場合はどちらでもか まいません). function-name + 0x103のような単純な式を使うこ とができます.

割り込みされたカーネルから処理を続行するためには,

c

とタイプするだけです. スタックのトレースには

trace

とします.

Note: DDB にホットキーで入った場合は, カーネルはその (ホットキーの) 割り込み の処理を行っていますのでスタックトレースは あまり役にたたないことに注 意してください.

ブレークポイントを削除したい場合は,

del
del address-expression

とします. 最初の形式はブレークポイントにヒットしたすぐ後で使うことが でき, 現在のブレークポイントを削除します. 2番目の形式では任意のブレー クポイントを削除することができますが, 次の形式で得られるような正確な アドレスを与えることが必要です.

show b

カーネルをシングルステップ実行させるには

s

としてみてください. これは関数呼出し先までステップ実行 (step into function) するでしょう. 次のステートメントが終了するまでのDDBトレースは

n

によっておこなうことができます.

Note: これは gdbnext 命令とは異ります. gdb finish命令と似ています.

メモリ上のデータを調べるには (例として) 次のようにします.

x/wx 0xf0133fe0,40
x/hd db_symtab_space
x/bc termbuf,10
x/s stringbuf
word/halfword/byte 単位でアクセスをおこない, hex (16進) /dec (10進) / char (文字) /string (文字列) で表示します. カンマの後ろの数字はオブジェク トカウントです. 次の 0x10個の要素を表示するには, 単純に
x ,10

とします. 同様に次のように使うことができます.

x/ia foofunc,10
foofunc の最初の 0x10個の命令語をディスアセンブルし, foofunc の先頭からのオフセットとともに表示します.

メモリの内容を変更するには writeコマンドを使います.

w/b termbuf 0xa 0xb 0
w/w 0xf0010030 0 0

コマンドモディファイアの (b/h/w) はデータを 書くサイズを定義し, これに続く最初の式は書き込むアドレス, 残りがこれ に続く連続するメモリアドレスに書き込まれるデータになります.

現在のレジスタ群の内容を知りたい場合は

show reg

とします. また, 単一のレジスタの値を表示するには, 例えば

p $eax
とします. また値の変更は
set $eax new-value

とします.

DDBからカーネルの関数を呼び出す必要がある場合は, 単に

call func(arg1, arg2, ...)

とします. return 値が出力されます.

動いているプロセスの ps(1) スタイルの概要は

ps

です.

カーネルの失敗の原因の調査が終わったらリブートすべきです. それまでの 不具合によりカーネルのすべての部分が期待するような 動作をしているわけ ではないということを忘れないでください. 以下のうちいずれかの方法でシ ステムのシャットダウンおよびリブートを行ってください.

call diediedie()

カーネルをコアダンプしてリブートしますので, 後で kgdbによってコアの高 レベル解析をすることができます. このコマンドは通常 continue命令にエイリアスされています. panicにエイリアスされている

call boot(0)

は動いているシステムを `clean' に shut downするよい方法です. すべて のディスクを sync()して最後にリブートします. ディスクとカー ネルのファイルシステムインタフェースが破損していない限り, ほぼ完全 に `clean'にシャットダウンするよい方法でしょう.

call cpu_reset()

は大惨事を防ぐための最後の手段で 「赤い大きなボタン」 を押すのとほとんど 同じです.(訳注: リセットボタンを押すのとほぼ同じであるという意味です)

短いコマンドの要約は

help

をタイプします. ただし, デバッグセッションのために ddb(4) の マニュアルページのプリントアウトを用意しておくことを 強くお奨めします. カーネルのシングルステップ中にオンラインマニュアルを 読むことは難しい ということを覚えておいてください.