FreeBSD ハンドブック : カーネルデバッグ : kgdbによるカーネルのクラッシュダンプのデバッグ
Previous: カーネルデバッグ
Next: 突然ダンプした場合の解析

20.1. kgdbによるカーネルのクラッシュダンプのデバッグ

ここではクラッシュダンプ (crash dump : 訳注 この文脈では kernel 自身 の異常によって停止した場合に出力されるイメージを指します) によるカー ネルデバッグの方法を示します.

ここではダンプするための十分なスワップ (swap) の容量があるものとし ます. もし複数のスワップパーティションを持ち, 最初のパーティションがダンプ を保持するのに十分な大きさを持たない場合は別のダンプデバイスを使うよ うに (config kernel 行で) カーネルのコンフィグをおこなうか, dumpon(8)コマンドを使って別のデバイスを示すことができます. スワップ をおこなわないデバイスへのダンプ, 例えばテープへのダンプは現在サポートさ れていません. カーネルのコンフィグは config -g によって行っ てください. FreeBSDカーネルのコンフィグレーション には FreeBSDのカーネルの設定の詳細がありますので参照してください.

dumpon(8)コマンドを使ってどこへダンプするかカーネルに伝えて ください(swapon(8)によってそのパーティションがスワップとして設定された 後でなければならないことに注意してください). これは普通は /etc/sysconfig/etc/rcで設定されます. あるいは 別の方法としてカーネルコンフィグレーションファイルの `config'行の `dump'節 で ダンプデバイスをハードコードすることができます. この方法はあまりよくは ありません. カーネルがブート時に crash する場合のクラッシュダンプを取り たい時だけ使うべきです.

Note: 以下では `kgdb'という用語は gdbを カーネルデバッグモードで動かしていることを意味します. gdb-kオプションをつけて起動するか kgdbという名前でリン クして起動することでこのモードになります. デフォルトでは このリンク は作られていません. また, このアイデアは GNU関係者たちが彼らのツール を別の名前で呼び出した時に異なった動作をするということを好まない, と いう点で不評です. あるいは将来この機能を廃止することになるかもしれません.

カーネルを作った時にそのコピーを kernel.debugという名前で作 りましょう. また, オリジナルに対して strip -dを実行します. オリジナルを普通にインストールします. また strip していないカーネル も同様にインストールすることができますが, シンボルテーブルの参照時間 がいくつかのプログラムでは劇的に増加するでしょう. また, カーネル全体 はブート時に読み込まれスワップアウトされないため数メガバイトの物理メ モリが無駄になります.

例えばブートプロンプトで新しいカーネルの名前をタイプすることによって, 新しいカーネルをテストした場合で, 再びシステムを動かすのに別のカーネ ルで立ち上げることが必要な場合はブートプロンプトで -sフラグ を使いシングルユーザの状態にしてください. そして以下のような操作をおこな います.

  fsck -p
  mount -a -t ufs       # /var/crash 用のファイルシステムを書き込み可能にする
  savecore -N /kernel.panicked /var/crash
  exit                  # ...マルチユーザモードへ移行
ここに示した savecore(8)は (現在動いているものとは別の) カー ネルのシンボル名の抽出をおこなうために使っています. 抽出はデフォルトで は現在動いているカーネルに対しておこなわれ, クラッシュダンプとカーネルシンボ ルのくい違いのためにまったく何もしません (訳注:そのためにオプション で実際にダンプをおこしたカーネルを指定します).

クラッシュダンプの起きた後に /sys/compile/WHATEVERへ行き kgdbを動かします. kgdb より次のようにします.

  symbol-file kernel.debug
  exec-file /var/crash/kernel.0
  core-file /var/crash/vmcore.0
こうすると, クラッシュダンプを使ってカーネルソースを他のプログラムと同様に デバッグすることができます.

次に kgdb での手順のセッションのログを示します. 長い行は読 みやすくするために改行しました. また, 参照のために行番号を入れてあり ます. ただし, これは実際の pcvtコンソールドライバの開発中の実際のエ ラーのトレースです.

   1:Script started on Fri Dec 30 23:15:22 1994
   2:uriah # cd /sys/compile/URIAH
   3:uriah # kgdb kernel /var/crash/vmcore.1 
	   4:Reading symbol data from /usr/src/sys/compile/URIAH/kernel...done.
   5:IdlePTD 1f3000
   6:panic: because you said to!
   7:current pcb at 1e3f70
   8:Reading in symbols for ../../i386/i386/machdep.c...done.
   9:(kgdb) where
  10:#0  boot (arghowto=256) (../../i386/i386/machdep.c line 767)
  11:#1  0xf0115159 in panic ()
  12:#2  0xf01955bd in diediedie () (../../i386/i386/machdep.c line 698)
  13:#3  0xf010185e in db_fncall ()
  14:#4  0xf0101586 in db_command (-266509132, -266509516, -267381073)
  15:#5  0xf0101711 in db_command_loop ()
  16:#6  0xf01040a0 in db_trap ()
  17:#7  0xf0192976 in kdb_trap (12, 0, -272630436, -266743723)
  18:#8  0xf019d2eb in trap_fatal (...)
  19:#9  0xf019ce60 in trap_pfault (...)
  20:#10 0xf019cb2f in trap (...)
  21:#11 0xf01932a1 in exception:calltrap ()
  22:#12 0xf0191503 in cnopen (...)
  23:#13 0xf0132c34 in spec_open ()
  24:#14 0xf012d014 in vn_open ()
  25:#15 0xf012a183 in open ()
  26:#16 0xf019d4eb in syscall (...)
  27:(kgdb) up 10
  28:Reading in symbols for ../../i386/i386/trap.c...done.
  29:#10 0xf019cb2f in trap (frame={tf_es = -260440048, tf_ds = 16, tf_\
  30:edi = 3072, tf_esi = -266445372, tf_ebp = -272630356, tf_isp = -27\
  31:2630396, tf_ebx = -266427884, tf_edx = 12, tf_ecx = -266427884, tf\
  32:_eax = 64772224, tf_trapno = 12, tf_err = -272695296, tf_eip = -26\
  33:6672343, tf_cs = -266469368, tf_eflags = 66066, tf_esp = 3072, tf_\
  34:ss = -266427884}) (../../i386/i386/trap.c line 283)
  35:283                             (void) trap_pfault(&frame, FALSE);
  36:(kgdb) frame frame->tf_ebp frame->tf_eip
  37:Reading in symbols for ../../i386/isa/pcvt/pcvt_drv.c...done.
  38:#0  0xf01ae729 in pcopen (dev=3072, flag=3, mode=8192, p=(struct p\
  39:roc *) 0xf07c0c00) (../../i386/isa/pcvt/pcvt_drv.c line 403)
  40:403             return ((*linesw[tp->t_line].l_open)(dev, tp));
  41:(kgdb) list
  42:398        
  43:399             tp->t_state |= TS_CARR_ON;
  44:400             tp->t_cflag |= CLOCAL;  /* cannot be a modem (:-) */
  45:401     
  46:402     #if PCVT_NETBSD || (PCVT_FREEBSD >= 200)
  47:403             return ((*linesw[tp->t_line].l_open)(dev, tp));
  48:404     #else
  49:405             return ((*linesw[tp->t_line].l_open)(dev, tp, flag));
  50:406     #endif /* PCVT_NETBSD || (PCVT_FREEBSD >= 200) */
  51:407     }
  52:(kgdb) print tp
  53:Reading in symbols for ../../i386/i386/cons.c...done.
  54:$1 = (struct tty *) 0x1bae
  55:(kgdb) print tp->t_line
  56:$2 = 1767990816
  57:(kgdb) up
  58:#1  0xf0191503 in cnopen (dev=0x00000000, flag=3, mode=8192, p=(st\
  59:ruct proc *) 0xf07c0c00) (../../i386/i386/cons.c line 126)
  60:       return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
  61:(kgdb) up
  62:#2  0xf0132c34 in spec_open ()
  63:(kgdb) up
  64:#3  0xf012d014 in vn_open ()
  65:(kgdb) up
  66:#4  0xf012a183 in open ()
  67:(kgdb) up
  68:#5  0xf019d4eb in syscall (frame={tf_es = 39, tf_ds = 39, tf_edi =\
  69: 2158592, tf_esi = 0, tf_ebp = -272638436, tf_isp = -272629788, tf\
  70:_ebx = 7086, tf_edx = 1, tf_ecx = 0, tf_eax = 5, tf_trapno = 582, \
  71:tf_err = 582, tf_eip = 75749, tf_cs = 31, tf_eflags = 582, tf_esp \
  72:= -272638456, tf_ss = 39}) (../../i386/i386/trap.c line 673)
  73:673             error = (*callp->sy_call)(p, args, rval);
  74:(kgdb) up
  75:Initial frame selected; you cannot go up.
  76:(kgdb) quit
  77:uriah # exit
  78:exit
  79:
  80:Script done on Fri Dec 30 23:18:04 1994
上の出力についてのコメントをします.

line 6:

これは DDB (後述) からのダンプです. このため ``because you said to!'' という panicコメントがつき, ページフォルトのト ラップによって DDBに入ったことが原因の, やや長いスタックトレー スがあります.

line 20:

スタックトレースでのこれは trap()関数の位置で す.

line 36:

新しいスタックフレームの使用を指定しています. これは現 在は必要ありません. trapの場合ではスタックフレームは正 しい場所を指していると考えられます. (私は新しいコアダンプ を持っていません. 私のカーネルは長い間 panicを起こしていま せん.) ソースコードの 403行を見ると,``tp''ポインタのアク セスが失敗しているか配列のアクセスが範囲外である可能性が高 いことがわかります.

line 52:

怪しいポインタですが, アクセスは正常におこなえました.

line 56:

ところが, 明らかにポインタはゴミを指しています. これで エラーを見つけました! (ここのコードの部分からはよくわかり ませんが, tp->t_lineはコンソールデバイスの規定 する行を参照しているので, もっと小さな整数でなければなりませ ん. )


FreeBSD ハンドブック : カーネルデバッグ : kgdbによるカーネルのクラッシュダンプのデバッグ
Previous: カーネルデバッグ
Next: 突然ダンプした場合の解析
FreeBSD Home Page
www@freebsd.org
Updated May 23, 1997