Windows Vista上のVMware Serverで、カーネルデバッグ

VMwareにインストールした2つのFreeBSDを、仮想シリアルポートでつなげて、カーネルデバッグをする方法。デバッグする対象のFreeBSDをtarget、デバッグするFreeBSDをhostとする。

いくつかのweb上のドキュメントでは、DDBGDBが連携するという記述があるが、これは古いもののようで、現在の方法はGDBのみでよいようだ。最近のものでは遡れないが、20040710の/usr/src/UPDATINGの記述など参照。

2つのFreeBSD(target & host)

VMware上に1つのFreeBSD(target)を構成し、カーネルを再構築する。少なくとも

options         KDB
options         GDB

が必要。カーネルコンパイルした、/usr/obj/usr/src/sys/XXX は後で必要になるので、そのまま置いておくべき。

FreeBSD(target)はいったんシャットダウン。VMwareの仮想シリアルをUse nameed pipe: \\.\pipe\com_1, This end is the client. The oter side is a virtual machine.で構成する。

VMwareのマシンをコピーする方法は、もっと洗練された方法があるのかもしれないが、とりあえずディレクトリごとコピーする。VMwareからみれるようにしたら(Open virtual machine...から選べばよい)、Virtual machine nameなどを変更して、混乱しないようにする。あとは、仮想シリアルポートの構成を、This end is the serverにして起動。最初の起動で、何か文句を言われるが、saveを選択すれば、その後は問題ない。起動したら、ネットワークの設定(IP アドレスなど)を変更することを忘れずに。

この状態で、targetとhostは、クロスのシリアルケーブルで結ばれた状態になっている。

kgdb をリモートから起動してカーネルデバッグ

まず、hostマシンを通常のように起動し、カーネルコンパイルしたディレクトリ(/usr/obj/usr/src/sys/XXXなど)に移動する。

次に、targetマシンを起動する。最初の起動時に6を押して、boot loaderのプロンプトに行く。そこで、boot -dで、起動する。するとデバイスを読み込み始める前の時点で、いったん停止する。

hostマシンにもどり、

% kgdb -r /dev/cuad0 kernel.debug

として、kgdbを起動する。ここでは、シリアル回線として/dev/cuad0がしていされ、シンボル付きのカーネルのイメージをkernel.debugとして指定している。/dev/cuad0のパーミッションは要注意。うまくいくと、

% kgdb -r /dev/cuad0 kernel.debug
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so: Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Switching to remote protocol
0xc06c08fb in kdb_enter (msg=0x2a "") at cpufunc.h:60
60              __asm __volatile("int $3");
#0  0xc06c08fb in kdb_enter (msg=0x2a "") at cpufunc.h:60
60              __asm __volatile("int $3");
(kgdb) 

となって、breakpointの設定や、ソースレベルのステップごとの実行が出来るようになる。基本的にはgdbと同じらしい。たとえば、

(kgdb) list
55      #if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
56
57      static __inline void
58      breakpoint(void)
59      {
60              __asm __volatile("int $3");
61      }
62
63      static __inline u_int
64      bsfl(u_int mask)
(kgdb) 

のように、どこかで読み込まれた/usr/src/sys/i386/include/cpufunc.hのbreakpoint関数で止まっているようだ。