前回から、Renode という QEMU に似たオープンソースのエミュレータを試してます。
前回は、インストールとSTM32のサンプルソースの実行までをやりました。
今回は、GDB で接続して、デバッグしてみます。
それでは、やっていきます。
参考文献
はじめに
「QEMUを動かす」の記事一覧です。良かったら参考にしてください。
QEMUを動かすの記事一覧
まず、Renode の公式サイトは以下です。
https://renode.io/
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ファイルでデバッグする
以前、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
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 の動作が怪しい気がします。
次回は、バイナリファイルで動作しない原因を見ていこうと思います。
この記事が誰かの役に立てば嬉しいです。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。