前回から、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 67 for (src = &_data_loadaddr, dest = &_data; (gdb) c
GDB で接続すると、エントリポイントで停止した状態になりました。c(continue)で実行を開始すると、「hello world!」が出力されました。

ですが、このエミュレーションの開始は、ドキュメントに書かれている、3つ目の方法のような挙動です。
renode-config.resc ファイルには、以下のようになっています。
machine StartGdbServer 3333
Renode のドキュメントには、3つ目の方法にするには、以下のようにするとあります。
machine StartGdbServer 3333 true
もしかすると、以前は、デフォルトが false だったけど、今は、デフォルトが true になったとかかもしれません。
とにかく、GDB で接続ができました。
以前作ったELFファイルでデバッグする
以前、 のルーレットゲームのサンプルソースを使って、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 107 break;

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 の動作が怪しい気がします。
次回は、バイナリファイルで動作しない原因を見ていこうと思います。
この記事が誰かの役に立てば嬉しいです。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。