Linuxカーネルのテスト実行とデバッグ (2) :GDB編

QEMUをカーネルの開発に使うことのメリットの1つとして、GDBによるデバッグが簡単にできることがあります。これは、GDBのリモートデバッグ機能を使用します。リモートデバッグ機能は、もとをたどれば、別のマシンで動いている(主に)組込みシステムをデバッグするために開発された機能で、対象システムにGDBと通信するためのスタブを組み込み、シリアルラインを介して通信してデバッグするというものでした。現在では、TCP/IPでの通信もサポートされており、QEMUにはそのスタブが組み込まれており、QEMU上で実行するプログラムをGDBでデバッグできるようになっています。

GDBでのLinuxカーネルのデバッグについては、今は以下にしっかりとした情報がまとまっていました。
https://www.kernel.org/doc/html/v4.12/dev-tools/gdb-kernel-debugging.html
ここに書かれている手順に従ってやってみましょう。

カーネルの準備

カーネルのコンフィグでは、CONFIG_GDB_SCRIPTSと(もしあれば)CONFIG_FRAME_POINTERをセットし、CONFIG_DEBUG_INFO_REDUCEDは切る、とのことです。これらのパラメータは、Kernel hackingからCompile-time checks and compiler optionsに移動したところにあります。以下は menuconfig の画面になりますが、

  • 2行目 Reduce debugging information … CONFIG_DEBUG_INFO_REDUCED
  • 5行目 Provide GDB scripts for kernel debugging … CONFIG_GDB_SCRIPTS
  • 17行目 Compile the kernel with frame pointers … CONFIG_FRAME_POINTER

という対応になっています。なお、2~5行目が表示されていない場合は、1行目の Compile the kernel with debug info を選択すると表示されます。

ちなみに、パラメータがどこのあるかわからない場合は、検索することもできます。menuconfig ではキーボードで / を入力すると、以下の画面が出てきますので、検索したいパラメータまたはキーワードを入力します。

すると、以下のようにどこにあるか (Location:) どのように表示されているか (Prompt:) を教えてくれます。

QEMUとGDBの接続

QEMUをGDBと接続するには、-s オプションを付けてQEMUを起動します。実行開始時からデバッグしたい場合は、-S (大文字のS) オプションもつけます。

  • -s は -gdb tcp::1234 のショートカットで、TCPポート 1234 でGDBサーバを起動します。
  • -S はプログラムの実行を開始せずに待機します。

では、早速 -s -S オプションをつけて、QEMU を実行してみましょう。

待機状態になっていますので、何も起こりません。別の端末からGDBを実行します。

なにやら怒られてしまいました。.gdbinitにadd-auto-load-safe-pathを設定しなさい、ということなので、その通りにします。

もう一度GDBを起動しますが、今度は違うエラーが出ます。

解決方法を探したところ、以下にある情報で解決できました:
https://github.com/cyrus-and/gdb-dashboard/issues/1

ホストOSはCentOS 7で、付属のGDBバージョン7.6ではちょっと古いのが原因だったのですが、~/.gdbinit.dにgdb/python/lib/gdb/FrameDecorator.pyを置き、.gdbinitの中身を以下にするとエラーはなくなりました。

GDBでのデバッグ

GDBの側でQEMUと接続するには target remote :1234 と入力します。その後で、適当なブレークポイントを設定し、c (continue) と打てば、QEMU側で実行が始まり、ブレークポイントに到達したところで、GDBに戻ります。

ブレークポイント削除後にc を打てば、QEMU上でLinuxカーネルは実行を継続します。実行中にカーネルの実行を中断したければ、GDB側で Ctrl-C を打つと、GDBのプロンプトが表示され、カーネルの実行状態を調べることができます。

おわりに

今回は、QEMUとGDBを接続し、GDBでLinuxカーネルのデバッグをする方法を紹介しました。CONFIG_GDB_SCRIPTS は、カーネル内の状態を表示するためのコマンドを提供しており、GDBで実行できるコマンドは apropos lx で表示できます。カーネルの実行時の内部状態を調べるのはこれまで面倒でしたが、かなり容易に調べられるようになっていますね。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です