NetBSD ドキュメンテーション: GDB を使い NetBSD カーネルをデバッグする HOWTO をQEMUでサクッと試すためのHowtoです。
前提
- 先に QEMUのgdbserver機能でNetBSD kernelをデバッグする を終えて下さい。こちらの方が難易度(ハマり度)が低いですし、こちらに載っているビルド方法などの手順は本記事でも必要になります。
- Linux (Ubuntu 17.10), macOS (High Sierra) で検証済みです。Windowsや他OSでの動作報告お待ちしております!
注意事項
NetBSD-currentはkgdbが壊れていて動作しません。リリース版のソースか、2017/08/15 08:35:56 より前のソースを使って下さい。(currentではこのコミット以外にも複数の問題があるようです)
実用面では、QEMUでkgdbを使う意味はありません[1]。QEMU gdbserverに勝るメリットが無いためです[2]。このHowtoの目的は、kgdbの正常な挙動を理解することです。その知識は物理マシンでkgdbを使う際に役立つと思います(実際自分がそうだった)。逆に既に物理マシンで問題なくkgdbを使えている方には不要なHowtoでしょう。
(注釈 [1]: ただしkgdb自体のデバッグをするためにQEMU上でkgdbを使うのは有意です。QEMU gdbserver+kgdbでKGDB自体(kgdb_stub.c など)のデバッグが可能になります。[2]: qemuの方がデバッグできる範囲が広い(kgdb_stub.c、kgdb_connect() の前、etc)、qemuの方が通信が速い、後述するような「中断できない」などの制限が無い)
kgdbを有効にしたカーネルのビルド
GENERICカーネルコンフィグ を編集して、
- 最適化無効
- DDB無効
- KGDB有効、
KGDB_DEVRATE=115200
にしてビルドします。
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 4170eaa92a3..e751a603b39 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -104,13 +104,13 @@ options DIAGNOSTIC # inexpensive kernel consistency checks
# Because gcc omits the frame pointer for any -O level, the line below
# is needed to make backtraces in DDB work.
#
-makeoptions COPTS="-O2 -fno-omit-frame-pointer"
-options DDB # in-kernel debugger
+makeoptions COPTS="-O0 -fno-omit-frame-pointer"
+#options DDB # in-kernel debugger
#options DDB_COMMANDONENTER="bt" # execute command when ddb is entered
#options DDB_ONPANIC=1 # see also sysctl(7): `ddb.onpanic'
options DDB_HISTORY_SIZE=512 # enable history editing in DDB
-#options KGDB # remote debugger
-#options KGDB_DEVNAME="\"com\"",KGDB_DEVADDR=0x3f8,KGDB_DEVRATE=9600
+options KGDB # remote debugger
+options KGDB_DEVNAME="\"com\"",KGDB_DEVADDR=0x3f8,KGDB_DEVRATE=115200
makeoptions DEBUG="-g" # compile full symbol table for CTF
#options SYSCALL_STATS # per syscall counts
#options SYSCALL_TIMES # per syscall times
0x3f8
はx86での I/Oアドレス で com0を表します。
ビルド後、カーネルを仮想マシンにインストール(scp -P10022 ${OBJDIR}/sys/arch/amd64/compile/GENERIC/netbsd root@localhost:/netbsd
)後 reboot
して、正常に起動できるか確認後 poweroff
します。
com0を使う修行
一旦読み飛ばして頂いて大丈夫です。ハマったら読んでみて下さい。
qemu-system-x86_64 -rtc base=utc -m 256 -hda netbsd.qcow2 -net nic -net user,hostfwd=tcp::10022-:22 -serial telnet::4444,server
で仮想マシンを起動します。QEMUのオプションについてはカーネルデバッグで使うQEMUオプションチートシートを参考にして下さい。別ターミナルで telnet localhost 4444
でQEMUに接続すると、QEMUウィンドウが表示されてNetBSDがブートします。
ブート中に流れるdmesgに com0: kgdb
が表示されていることを確認します。
/var/run/dmesg.boot
:
...
[ 1.0536313] iic0 at piixpm0: I2C bus
[ 1.0536313] vga0 at pci0 dev 2 function 0: vendor 1234 product 1111 (rev. 0x02)
[ 1.0536313] wsdisplay0 at vga0 kbdmux 1: console (80x25, vt100 emulation), using wskbd0
[ 1.0536313] wsmux1: connecting to wsdisplay0
[ 1.0536313] drm at vga0 not configured
...
[ 1.0536313] lpt0 at isa0 port 0x378-0x37b irq 7
[ 1.0536313] com0 at isa0 port 0x3f8-0x3ff irq 4: ns16550a, working fifo
[ 1.0536313] com0: kgdb
[ 1.0536313] attimer0 at isa0 port 0x40-0x43
...
reboot
後、QEMUウィンドウのboot promptで consdev com0
と入力します。
左のターミナル (com0) がコンソールになりました。コンソールをQEMUウィンドウに戻すには consdev pc
と入力すれば良いです。このままcom0で boot
と打つとcom0にdmesgが流れて。login:
が表示されます。
dmesgには wsdisplay0 at vga0 kbdmux 1: console
が無くなり、com0: console
が現れます。
...
[ 1.0301096] iic0 at piixpm0: I2C bus
[ 1.0301096] vga0 at pci0 dev 2 function 0: vendor 1234 product 1111 (rev. 0x02)
[ 1.0301096] wsdisplay0 at vga0 kbdmux 1
[ 1.0301096] wsmux1: connecting to wsdisplay0
[ 1.0301096] wskbd0: connecting to wsdisplay0
[ 1.0301096] drm at vga0 not configured
[ 1.0301096] wm0 at pci0 dev 3 function 0: Intel i82540EM 1000BASE-T Ethernet (rev. 0x03)
...
[ 1.0301096] lpt0 at isa0 port 0x378-0x37b irq 7
[ 1.0301096] com0 at isa0 port 0x3f8-0x3ff irq 4: ns16550a, working fifo
[ 1.0301096] com0: console
[ 1.0301096] com0: kgdb
[ 1.0301096] attimer0 at isa0 port 0x40-0x43
...
kgdbに接続する
仮想マシンを qemu-system-x86_64 -rtc base=utc -m 256 -hda netbsd.qcow2 -net nic -net user,hostfwd=tcp::10022-:22 -serial telnet::4444,server,nowait
で起動します。QEMUのオプションについてはカーネルデバッグで使うQEMUオプションチートシートを参考にして下さい。
QEMUウィンドウでスペースを押して5を選択した後、boot -d
で起動すると kgdb waiting...
が表示されたます。
この状態でホストのクロスgdbから target remote :4444
を実行すると、kgdbに接続されてデバッグが開始されます。
NetBSDのkgdbはクセが強く、色々気をつけるべきことがあります。
- gdbを一度切断すると、二度と接続できなくなります。もう再接続するには仮想マシンを再起動する必要があります。
-
continue
した後、Ctrl-Cによる中断ができません。うっかり押してしまうと再接続できなくなり、仮想マシンの再起動が必要になります。公式HOWTO を見ると、昔はCtr-Cで中断できたようです。Regressionしてるっぽいです。(調査中です) - 上の性質から、
continue
する前にbreak
を入れることが必須です。
gdbを直接使うは非常に使いづらいので、テキストエディタやIDEから使いましょう。CLionから使うHowtoを近日中に公開予定です。
ライセンス
この 作品 は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。
関連するソフトウェアの公式ドキュメントのメンテナの方へ:この記事の内容を公式ドキュメントに記載して頂ける場合、この記事にコメントして頂くか、twitter @wata_ash にご連絡下さい。