QEMU上のLinuxカーネルをGDBでデバッグする

プログラムがセグメンテーションフォルトで不正終了した場合に、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オプションを解除する為に指定する。

5. 実行例

以下はscreenコマンドを介してQEMUとGDBを実行した画面である。 start_kernelでbreakしていることが確認できる。

GDBのnコマンドで処理を進めていくとconsole_init()実行直後にシリアルコン ソールへ文字が出力されることを確認できる。

cで処理を続行するとpanicが発生してしまった。btコマンドやupコマンドで原 因となる箇所を遡ると、ルートファイルシステムを指定していない為に発生し ていることが分かる。