2019-09-22

FreeBSDのカーネルのリモートデバッグをおこなう

FreeBSDのブートプロセスをみる』(白崎博生、UNIX MAGAZINE COLLECTION、2006年)を追体験しながら、カーネルを勉強しようと考えています。連載当時はFreeBSD 5.1でしたが、今はFreeBSD 12.0です。細かいところで記述内容と合わない点があります。まずは連載最後の17回を参考に、カーネルデバッグの環境を整えておこうと思います。

カーネルデバッガDDBが起動できるようなカーネルに入れ換える作業は、特に問題ありませんでした。

つぎはリモートデバッグの環境を準備しようと思います。書籍の記述ではVMwareを利用していますが、僕はVirtualBoxを使おうと思います。VMwareだろうが、VirtualBoxだろうが、もしくは仮想環境ではなく実機であろうが、考え方は変わらない筈です。その筈なのですが、当初うまくいかず苦労してしまいました。しかし最終的にリモートデバッグ環境ができたので、結果オーライという感じです。

もし実機を使ってリモートデバッグ環境を整えるなら、2台のマシン間をRS-232Cのヌルモデムケーブルで繋ぐことになるでしょう。仮想環境であれば、2台のゲスト環境のCOM1ポートを「仮想的」に接続されているように見せかける必要があります。それが連載記事でも紹介されている、名前付きパイプを使用する方法です。記事ではVMwareの設定としてシリアルポートを名前付きパイプとして設定しています。VirtualBoxでもシリアルポートを名前付きパイプとして設定できるので、当初この方法で2台のゲスト環境を接続するつもりでした。ところがうまくいきません。どううまくいかないかというと、リモートデバッグ環境からターゲット側への接続ができないというエラーが出てしまうのです。そもそもVirtualBoxでは無理なのかと思いましたが、Webで「Freebsd kernel remote debugging. Part1」という情報を発見しました。バージョンが書かれていませんが、成功した事例と言えるでしょう。

VirtualBoxではなくQEMUを使った事例として「FreeBSDのオンラインカーネルデバッグ with QEMU」という情報も見つけました。こちらはQEMUにしかない機能を利用しているので、同じことをVirtualBoxで実現することはできませんが、参考になります。

最終的にVirtualBoxの設定を次のようにすることでリモートデバッグ環境が出来上がりました。

  1. 使用したVirtualBoxは「バージョン 6.0.12 r133076 (Qt5.6.2)」です。
  2. FreeBSDのカーネルデバッグされる側を「ターゲット」と呼ぶことにします。
  3. GDBでデバッグコマンドを操作する側を「デバッガ」と呼ぶことにします。
  4. 「ターゲット」ではVirtualBoxでシリアルポートを利用できるように設定しておきます。
    1. 「ポートモード」を「TCP」にします。
    2. 「存在するパイプ/ソケットに接続」のチェックを外します。
    3. 「パス/アドレス」を設定します。他のアプリケーションと衝突しなければなんでも良いでしょう。僕は「35790」にしました。
  5. 「デバッガ」ではシリアルポートを使わないので、有効にする必要はありません。

上述した設定をして「ターゲット」と「デバッガ」のゲスト環境を起動します。「ターゲット」でログインプロンプトが出たら、CtrlとPrintScrキーを同時に押してカーネルデバッガに入ります。そして「gdb」コマンドを入力してリモートからの接続を待機させます。
FreeBSD/amd64 (target) (ttyv0)

login: KDB: enter: manual escape to debugger
[ thread pid 12 tid 100006 ]
Stopped at       0xffffffff80bf955b = kdb_enter+0x3b:   moveq   $0,0xffffffff81f7cbe8 = kdb_why
db> gdb
(ctrl-c will return control to ddb)
Switching to gdb back-end
一方「デバッガ」ではgdbを起動し、「ターゲット」に接続します。ここで接続先の指定はTCP/IPアドレスとポート番号を使用します。注意が必要なのは、TCP/IPアドレスは、「ターゲット」のゲスト環境のFreeBSDに割り当てられたアドレスではなく、ホスト環境であるWindows10のアドレスです。
furusawa@debugger:~ % kgdb /boot/kernel/kernel
GNU gdb (GDB) 8.3 [GDB v8.3 for FreeBSD]
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-portbld-freebsd12.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /boot/kernel/kernel...
Reading symbols from /boot/kernel/kernel.debug...
(kgdb) target remote 192.168.1.14:35790
Remote debugging using 192.168.1.14:35790
warning: remote target does not support file transfer, attempting to access files from local filesystem.
Reading symbols from /boot/kernel/intpm.ko...
warning: the debug information found in "/usr/lib/debug//boot/kernel/intpm.ko.debug" does not match "/boot/kernel/intpm.ko" (CRC mismatch).

(No debugging symbols found in /boot/kernel/intpm.ko)
Reading symbols from /boot/kernel/smbus.ko...
warning: the debug information found in "/usr/lib/debug//boot/kernel/smbus.ko.debug" does not match "/boot/kernel/smbus.ko" (CRC mismatch).

(No debugging symbols found in /boot/kernel/smbus.ko)
kdb_enter (why=0xffffffff812fae28 "break", msg=<optimized out>)
    at /usr/src/sys/kern/subr_kdb.c:479
479                     kdb_why = KDB_WHY_UNSET;
(kgdb)
このように「ターゲット」と「デバッガ」の接続が確立されました。これでリモートデバッグ環境が出来たことになります。

試しにシステムコール「sys_mkdir」にブレークポイントを仕掛けてみます。そして「ターゲット」のコマンドラインでコマンド「mkdir」を実行しようとすると、ブレークポイントで停止してくれました。成功です。
(kgdb) b sys_mkdir
Breakpoint 1 at 0xffffffff80c90614: file /usr/src/sys/kern/vfs_syscalls.c, line 3582.
(kgdb) c
Continuing.
[New Thread 100086]
[New Thread 100063]
[Switching to Thread 100086]

Thread 78 hit Breakpoint 1, sys_mkdir (td=0xfffff80003fd8580,
    uap=0xfffff80003fd8940) at /usr/src/sys/kern/vfs_syscalls.c:3582
3582            return (kern_mkdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE,
(kgdb) list
3577    #endif
3578    int
3579    sys_mkdir(struct thread *td, struct mkdir_args *uap)
3580    {
3581
3582            return (kern_mkdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE,
3583                uap->mode));
3584    }
3585
3586    #ifndef _SYS_SYSPROTO_H_
(kgdb) c
Continuing.
これでFreeBSDのカーネルをリモートデバッグするための環境が手に入りました。この環境を利用して『FreeBSDのブートプロセスをみる』を読んでいこうと思います。

0 件のコメント:

コメントを投稿