プログラムがセグメンテーションフォルトで不正終了した場合に、GDBで原因 調査するというのはよく聞く話である。しかし、こういったソフトウェア開発 の後行程で使用するだけではなく、前行程でも使うべきである。これは挙動が よく分からないプログラムの動作確認にGDBが有効であるからだ。 今回は特にprint文が動作しない段階のLinuxカーネルの動作をGDBで確認する。 ただし、あくまでQEMU上での動作である為、QEMUでサポートしていないハード やQEMUが再現しきれていないハードの動作部分については未対応である。そう いった場合はICEなどの治具を用いる必要がある。
1. カーネルコンフィグの設定
CONFIG_DEBUG_KERNELを有効にする。
Symbol: DEBUG_KERNEL [=y] Type : boolean Prompt: Kernel debugging Location: -> Kernel hacking Defined at lib/Kconfig.debug:315 Selected by: EXPERT [=n]
CONFIG_DEBUG_INFOを有効にする。この設定でデバッグシンボルが生成される。
Symbol: DEBUG_INFO [=y] Type : boolean Prompt: Compile the kernel with debug info Location: -> Kernel hacking -> Compile-time checks and compiler options Defined at lib/Kconfig.debug:120 Depends on: DEBUG_KERNEL [=y]
CONFIG_RELOCATABLEを無効にする。CONFIG_RELOCATABLEを無効にしない場合、 カーネルがメモリ上で再配置される。その際、デバッグシンボルに記載される アドレスと対応しなくなり、GDBがシンボルを解釈できなくなる。
Symbol: RELOCATABLE [=n] Type : boolean Prompt: Build a relocatable kernel Location: -> Processor type and features Defined at arch/x86/Kconfig:1711
2. QEMUの起動
qemu-system-i386を使用した場合、--kernelでLinuxカーネルイメージを指定 してやればQEMUは起動する。しかし、GDBを使用する場合は-Sと-gdbを使用し た方が使いやすい。
qemu-system-i386 --kernel linux-3.12.5/arch/x86/boot/bzImage \ -gdb tcp::10000 \ -S \ -nographic \ -append "console=ttyS0"
-nographicオプションでディスプレイ画面を無効に、-appendオプションでカー ネル起動パラメータを渡している。
2.1. -Sオプション
GDBがキックするまで待つオプション。GDB側でシンボルファイル読み込み等の 前処理を実行する場合に必要である。
2.2. -gdbオプション
GDBの接続方法を指定するオプション。-sオプションを用いた場合は-gdb tcp::1234と等価となる。今回はTCPポート番号10000を使用する。
3. GDBの起動
GDBは-xオプションで任意の操作を起動時に指定することができ、GDB起動毎に 手入力する手間を省ける。
gdb -x gdb.scr
GDBの-xオプションで指定するファイルの内容は以下である。
target remote localhost:10000 source linux-3.12.5 symbol-file linux-3.12.5/vmlinux b start_kernel la src c
3.1. target remoteコマンド
QEMUの-gdbオプションで指定した値を指定する。今回はQEMUとGDBは同一マシ ンで動作させるのでlocalhost:10000を指定する。
3.2. sourceコマンド
ソースコードのディレクトリを指定する。今回はLinuxカーネルのディレクト リのlinux-3.12.5を指定する。
3.3. symbol-fileコマンド
シンボル情報込みのバイナリを指定する。今回は圧縮前(かつstrip前)の vmlinuxを指定する。
3.4. bコマンド
breakpointを指定する。今回はstart_kernelを指定する。
3.5. la srcコマンド
ソースコードを表示する。
3.6. cコマンド
QEMUの-Sオプションを解除する為に指定する。
GDBのnコマンドで処理を進めていくとconsole_init()実行直後にシリアルコン ソールへ文字が出力されることを確認できる。
cで処理を続行するとpanicが発生してしまった。btコマンドやupコマンドで原 因となる箇所を遡ると、ルートファイルシステムを指定していない為に発生し ていることが分かる。