前回から、Renode という QEMU に似たオープンソースのエミュレータを試してます。
前回は、インストールとSTM32のサンプルソースの実行までをやりました。
今回は、GDB で接続して、デバッグしてみます。
それでは、やっていきます。
参考文献
はじめに
「QEMUを動かす」の記事一覧です。良かったら参考にしてください。
・第2回:STM32(ARM Cortex-M)をQEMUで動かす(ソースコード確認編)
・第3回:STM32(ARM Cortex-M)をQEMUで動かす(スタートアップルーチン編)
・第4回:STM32(ARM Cortex-M)をQEMUで動かす(リンカスクリプト編)
・第5回:STM32(ARM Cortex-M)のELFファイルの内容を確認する
・第6回:STM32(ARM Cortex-M)のELFファイル⇔バイナリの変換を行う
・第7回:STM32(ARM Cortex-M)のバイナリから構築したELFファイルをQEMUで動かす
・第8回:QEMUのビルドに必要なxpm(xPack Project Manager)について学ぶ
・第9回:QEMUをソースからビルドして動かす
・第10回:QEMUのソースコードを変更してSTM32の動作を変える
・第11回:QEMUに似たRenodeというOSSの組込みデバイスエミュレータを試す
・第12回:QEMUに似たRenodeでSTM32をGDBを使ってデバッグする ← 今回
まず、Renode の公式サイトは以下です。
Renode の公式のドキュメントは以下です。
https://renode.readthedocs.io/en/latest/
また、GitHub は以下です。
https://github.com/renode/renode
今回は、Renode を GDB を使って動かしていきます。
STM32のサンプルソースをデバッグする
それでは、早速、前回の続きで、STM32F4 の Discovery を対象として Renode を起動します。
前回とは異なり、Renode モニターで start はしません。Renode のドキュメントの GDB でデバッグを見ると、Renode は、3種類のエミュレーションの開始方法が用意されていると書かれています。
1つ目は Renode から start で開始する方法で、2つ目は GDB から monitor start で開始する方法で、3つ目は GDB から接続されると自動的に開始する方法です。
今回は、2つ目の GDB から monitor start と入力して開始する方法でやってみたいと思います。
$ ./renode renode-config.resc
別のコンソールを立ち上げて、GDB を起動していきます。
$ arm-none-eabi-gdb renode-example.elf (gdb) target remote :3333 reset_handler () at ../../cm3/vector.c:67 67for(src =&_data_loadaddr, dest =&_data;(gdb) c
GDB で接続すると、エントリポイントで停止した状態になりました。c(continue)で実行を開始すると、「hello world!」が出力されました。
ですが、このエミュレーションの開始は、ドキュメントに書かれている、3つ目の方法のような挙動です。
renode-config.resc ファイルには、以下のようになっています。
machine StartGdbServer 3333
Renode のドキュメントには、3つ目の方法にするには、以下のようにするとあります。
machine StartGdbServer 3333true
もしかすると、以前は、デフォルトが false だったけど、今は、デフォルトが true になったとかかもしれません。
とにかく、GDB で接続ができました。
以前作ったELFファイルでデバッグする
以前、Interface 2022年 7月号のルーレットゲームのサンプルソースを使って、QEMU で動かしました。
この ELFファイルを使って、Renode で動かしていきたいと思います。
まずは、Renode のディレクトリに、以前に作った ELFファイルのシンボリックリンクを作ります。1つ目が普通の ELFファイルで、2つ目は、一度バイナリファイルに変換して、シンボル情報などのデバッグ情報を削除して、ELFファイルに再構築したファイルです。
$ ln -s ~/eclipse-workspace/stm32f4discovery_sample/Debug/stm32f4discovery_sample.elf $ ln -s ~/eclipse-workspace/stm32f4discovery_sample/Debug/stm32f4discovery_sample_bin2elf_entry.elf
普通のELFファイルを動かしてみる
では、まずは、普通のELFファイルの方を、手動で Renode を起動していきます。
$ renode Gtk-Message: 21:29:43.731: Failed to load module "canberra-gtk-module" 21:29:44.6876[INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.15.0_portable/scripts/monitor.py (monitor) mach create 21:30:27.2465[INFO] System bus created. (machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl 21:30:49.7163[INFO] Reading cache 21:30:50.1987[INFO] sysbus: Loaded SVD: /tmp/renode-10320/b9a14342-eb23-457c-9175-699febb364f2.tmp. Name: STM32F40x. Description: STM32F40x. (machine-0) sysbus LoadELF @stm32f4discovery_sample.elf 21:31:19.4952[INFO] sysbus: Loading segment of 11000 bytes length at 0x8000000. 21:31:19.5196[INFO] sysbus: Loading segment of 360 bytes length at 0x8002AF8. 21:31:19.5199[INFO] sysbus: Loading segment of 256 bytes length at 0x2001F700. (machine-0) machine StartGdbServer 3333 21:31:38.0812[INFO] machine-0: GDB server with all CPUs started on port :3333
問題なく起動できていそうです。続いて、GDB で接続します。
$ arm-none-eabi-gdb stm32f4discovery_sample.elf (gdb) target remote :3333 Remote debugging using :3333 Reset_Handler () at ../startup.S:119 119 mrs r0, control (gdb) c Continuing. ^C Program received signal SIGTRAP, Trace/breakpoint trap. main () at ../main.c:107 107break;
GDB で接続すると、エントリポイントで停止した状態になりました。その後、c(continue)で実行開始しました。LED が見えないですが、Ctrl+C で、いったん停止すると main関数のどこかで止まったので、動いてそうです。
デバッグ情報の無いELFファイルを動かしてみる
普通の ELFファイルと同じように、手動で Renode で起動していきます。
$ renode Gtk-Message: 21:31:59.406: Failed to load module "canberra-gtk-module" 21:32:00.3045[INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.15.0_portable/scripts/monitor.py (monitor) mach create 21:32:20.0797[INFO] System bus created. (machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl 21:32:33.8938[INFO] Reading cache 21:32:34.3756[INFO] sysbus: Loaded SVD: /tmp/renode-10368/5f7902f5-f5f6-40d8-bda6-cc71e8ab32c4.tmp. Name: STM32F40x. Description: STM32F40x. (machine-0) sysbus LoadELF @stm32f4discovery_sample.elf 21:33:04.9895[INFO] sysbus: Loading segment of 11116 bytes length at 0x8000000. (machine-0) machine StartGdbServer 3333 21:33:18.2970[INFO] machine-0: GDB server with all CPUs started on port :3333
ELFファイルをロードしたときのログが普通の ELFファイルの場合と異なります。GDB を接続します。
$ arm-none-eabi-gdb stm32f4discovery_sample.elf (gdb) target remote :3333 Remote debugging using :3333 0x00000000 in ?? ()
エントリポイントまでいかず、0番地で起動しました。
Renode 側のログは以下のようになっていました。
21:35:26.6557[WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x4. 21:35:26.6559[WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x0. 21:35:26.6588[ERROR] cpu: PC does not lay in memory or PC and SP are equal to zero. CPU was halted. 21:35:26.6656[INFO] cpu: Setting initial values: PC = 0x0, SP = 0x0. 21:35:26.6664[WARNING] cpu: Patching PC 0x0 for Thumb mode. 21:35:26.6678[INFO] machine-0: Machine started.
STM32 の場合、4番地はリセットハンドラのアドレスが格納されていて、0番地はスタックポインタの初期値が格納されています。そこから読み出せなかった、という警告が出ています。
このデバッグ情報の無い ELFファイルは、最低限のリンカスクリプトで ELFファイルを作っています。それが原因かもしれません。
デバッグ情報の無い raw binary のバイナリファイルで動かしてみる
Renode のドキュメントの CPU環境の構築のところを見ると、Renode は、ELFファイルだけでなく、バイナリファイルのロードにも対応しているようです。やってみます。
まずは、バイナリファイルを同じように、シンボリックリンクを作ります。
$ ln -s ~/eclipse-workspace/stm32f4discovery_sample/Debug/stm32f4discovery_sample_objcopy.bin
では、このバイナリファイルを Renode で起動していきます。
$ renode Gtk-Message: 21:46:48.764: Failed to load module "canberra-gtk-module" 21:46:49.6671[INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.15.0_portable/scripts/monitor.py (monitor) mach create 21:46:59.5845[INFO] System bus created. (machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl 21:48:45.2759[INFO] Reading cache 21:48:45.7662[INFO] sysbus: Loaded SVD: /tmp/renode-10451/b58a73de-2638-46a1-9d68-515741ec08ce.tmp. Name: STM32F40x. Description: STM32F40x. (machine-0) sysbus LoadBinary @stm32f4discovery_sample_objcopy.bin The following methods are available: - Void LoadBinary (ReadFilePath fileName, UInt64 loadPoint, ICPU cpu = null) Usage: sysbus MethodName param1 param2 ... There was an error executing command'sysbus LoadBinary @/home/daisuke/svn_/renode/renode_1.15.0_portable/stm32f4discovery_sample_objcopy.bin' Parameters did not match the signature
単純にバイナリファイルを指定しただけではエラーになりました。ロードするアドレスを指定する必要があるようです。その後ろの ICPU?は分からないので、とりあえずアドレスだけ指定してみます。
(machine-0) sysbus LoadBinary @stm32f4discovery_sample_objcopy.bin 0x08000000 (machine-0) machine StartGdbServer 3333 21:57:01.2632[INFO] machine-0: GDB server with all CPUs started on port :3333
エラーは出なくなりましたが、正常な場合は、ロードされたというログが出ていたので、うまくいってないかもしれません。とりあえず GDB を接続してみます。
$ arm-none-eabi-gdb stm32f4discovery_sample_objcopy.bin "/home/daisuke/svn_/renode/renode_1.15.0_portable/stm32f4discovery_sample_objcopy.bin": not in executable format: file format not recognized (gdb) target remote :3333 Remote debugging using :3333 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file"command. 0x00000000 in ?? ()
Renode 側のログです。
21:58:16.4682[WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x4. 21:58:16.4686[WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x0. 21:58:16.4712[ERROR] cpu: PC does not lay in memory or PC and SP are equal to zero. CPU was halted. 21:58:16.4781[INFO] cpu: Setting initial values: PC = 0x0, SP = 0x0. 21:58:16.4786[WARNING] cpu: Patching PC 0x0 for Thumb mode. 21:58:16.4798[INFO] machine-0: Machine started.
先ほどと同じですね。
ELFファイルの場合は、情報が不足しているので、失敗しても仕方ないですが、バイナリファイルの場合は、情報が無いファイルなので、この結果は変だと思います。
おわりに
今回は、Renode で、GDB を使って動かしてみました。
GDB 自体は問題なく動きましたが、バイナリファイルについては Renode の動作が怪しい気がします。
次回は、バイナリファイルで動作しない原因を見ていこうと思います。
この記事が誰かの役に立てば嬉しいです。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。