このブログは、株式会社フィックスターズのエンジニアが、あらゆるテーマについて自由に書いているブログです。
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~5行目が表示されていない場合は、1行目の Compile the kernel with debug info を選択すると表示されます。
ちなみに、パラメータがどこのあるかわからない場合は、検索することもできます。menuconfig ではキーボードで / を入力すると、以下の画面が出てきますので、検索したいパラメータまたはキーワードを入力します。
すると、以下のようにどこにあるか (Location:) どのように表示されているか (Prompt:) を教えてくれます。
QEMUをGDBと接続するには、-s オプションを付けてQEMUを起動します。実行開始時からデバッグしたい場合は、-S (大文字の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の側で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 で表示できます。カーネルの実行時の内部状態を調べるのはこれまで面倒でしたが、かなり容易に調べられるようになっていますね。
コンピュータビジョンセミナーvol.2 開催のお知らせ - ニュース一覧 - 株式会社フィックスターズ in Realizing Self-Driving Cars with General-Purpose Processors 日本語版
[…] バージョンアップに伴い、オンラインセミナーを開催します。 本セミナーでは、...
【Docker】NVIDIA SDK Managerでエラー無く環境構築する【Jetson】 | マサキノート in NVIDIA SDK Manager on Dockerで快適なJetsonライフ
[…] 参考:https://proc-cpuinfo.fixstars.com/2019/06/nvidia-sdk-manager-on-docker/ […]...
Windowsカーネルドライバを自作してWinDbgで解析してみる① - かえるのほんだな in Windowsデバイスドライバの基本動作を確認する (1)
[…] 参考:Windowsデバイスドライバの基本動作を確認する (1) - Fixstars Tech Blog /proc/cpuinfo ...
2021年版G検定チートシート | エビワークス in ニューラルネットの共通フォーマット対決! NNEF vs ONNX
[…] ONNX(オニキス):Open Neural Network Exchange formatフレームワーク間のモデル変換ツー...
YOSHIFUJI Naoki in CUDAデバイスメモリもスマートポインタで管理したい
ありがとうございます。別に型にこだわる必要がないので、ユニバーサル参照を受けるよ...