Article

2017年8月29日

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 を実行してみましょう。

% qemu/x86_64-softmmu/qemu-system-x86_64 -s -S -m 256 -nographic -kernel linux-stable/arch/x86_64/boot/bzImage -append console=ttyS0 -initrd initrd.img

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

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

~% cat .gdbinit
add-auto-load-safe-path /home/shui/src/linux-stable/scripts/gdb/vmlinux-gdb.py

もう一度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の中身を以下にするとエラーはなくなりました。

% cat .gdbinit
python gdb.COMPLETE_EXPRESSION = gdb.COMPLETE_SYMBOL
python
import imp
gdb.FrameDecorator = imp.new_module('FrameDecorator')
end
#
add-auto-load-safe-path /home/shui/src/linux-stable/scripts/gdb/vmlinux-gdb.py

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 で表示できます。カーネルの実行時の内部状態を調べるのはこれまで面倒でしたが、かなり容易に調べられるようになっていますね。

About Author

追川 修一

1996年慶應義塾大学より博士(工学).2004年筑波大学大学院システム情報工学研究科助教授,2016年筑波大学システム情報系教授を経て,現在,株式会社フィックスターズに勤務.システムソフトウェア等に関する研究開発に従事.

Leave a Comment

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Recent Comments

Social Media