daisukeの技術ブログ

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

QEMUに似たRenodeでSTM32をバイナリファイルで動かす

前々回から、Renode という QEMU に似たオープンソースのエミュレータを試しています。

前回は、GDB で接続するところをやりましたが、バイナリファイルではうまく動きませんでした。

この記事では、バイナリファイルで動かない原因を調べて、その記録となります。

古いバージョンを使ったり、デバッグログを出して確認してみましたが、原因は分かりませんでした。後で役立つかもしれないので、記事として投稿しますが、有益な情報は無いと思います。

参考文献

GDBハンドブック

GDBハンドブック

Amazon

はじめに

「QEMUを動かす」の記事一覧です。良かったら参考にしてください。

QEMUを動かすの記事一覧

まず、Renode の公式サイトは以下です。

https://renode.io/

Renode の公式のドキュメントは以下です。

https://renode.readthedocs.io/en/latest/

また、GitHub は以下です。

https://github.com/renode/renode

今回は、Renode をバイナリファイルで動かしていきます。

古いバージョン(v1.9)のRenodeを試す

前回、気になったのは、Renode の開始方法が、Renode のドキュメントの GDB でデバッグ に書かれてる内容と異なっているところです。

ドキュメントには、Renode には、3種類のエミュレーションの開始方法が用意されていると書かれています。

1つ目は Renode から start で開始する方法で、2つ目は GDB から monitor start で開始する方法で、3つ目は GDB から接続されると自動的に開始する方法です。

しかし、今回試した Renode の v1.15 では、GDB を接続すると、勝手に開始してしまい、3つ目の方法しか実現できない状態です。

参考にさせてもらった以下のサイトでは、v1.9 を使っていて、上記の v1.15 の問題は無いようです。

interrupt.memfault.com

同じ v1.9 を使って、動作を確認したいと思います。

以下で、Renode のリリースバージョンを取得できます。

github.com

では、v1.9 をダウンロードして、ELFファイルや、バイナリファイルのシンボリックファイルを作ります。

$ wget https://github.com/renode/renode/releases/download/v1.9.0/renode-1.9.0.linux-portable.tar.gz
$ tar zxvf renode-1.9.0.linux-portable.tar.gz
$ cd renode_1.9.0+20200310git169a3c8_portable/
$ ln -s /home/daisuke/eclipse-workspace/stm32f4discovery_sample/Debug/stm32f4discovery_sample.elf
$ ln -s /home/daisuke/eclipse-workspace/stm32f4discovery_sample/Debug/stm32f4discovery_sample_bin2elf_entry.elf
$ ln -s /home/daisuke/eclipse-workspace/stm32f4discovery_sample/Debug/stm32f4discovery_sample_objcopy.bin

Renodeのv1.9で普通のELFファイルを動かす

それでは、v1.9 で起動していきます。まずは、普通の ELFファイルでやってみます。

$ ./renode
Gtk-Message: 14:56:39.420: Failed to load module "canberra-gtk-module"
14:56:43.9073 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.9.0+20200310git169a3c8_portable/./scripts/monitor.py
(monitor) mach create
14:57:49.7915 [INFO] System bus created.
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl 
14:58:20.7004 [DEBUG] Segment size automatically calculated to value 16MiB
14:58:20.7022 [DEBUG] Segment size automatically calculated to value 64KiB
14:58:20.7023 [DEBUG] Segment size automatically calculated to value 128KiB
14:58:20.8957 [DEBUG] Segment size automatically calculated to value 64KiB
14:58:21.0064 [INFO] Reading cache
14:58:21.0254 [WARNING] There was an error while loading index file. Cache will be rebuilt.
14:58:21.0383 [INFO] Downloading http://antmicro.com/projects/renode/svd/STM32F40x.svd.gz.
14:58:24.3527 [INFO] Downloading: http://antmicro.com/projects/renode/svd/STM32F40x.svd.gz
    Progress: 66% (48KiB/72.46KiB)
    Speed: 68.61KB/s.
14:58:24.5840 [INFO] Download done.
14:58:24.5863 [INFO] Decompressing http://antmicro.com/projects/renode/svd/STM32F40x.svd.gz.
14:58:24.5956 [INFO] Decompression done
14:58:25.0095 [INFO] sysbus: Loaded SVD: /tmp/renode-18101/34d954dc-2b85-45bb-b125-2abe0fbea430.tmp. Name: STM32F40x. Description: STM32F40x.
(machine-0) sysbus LoadELF @stm32f4discovery_sample.elf 
15:01:45.8758 [DEBUG] sysbus: Loading ELF /home/daisuke/svn_/renode/renode_1.9.0+20200310git169a3c8_portable/stm32f4discovery_sample.elf.
15:01:45.8901 [INFO] sysbus: Loading segment of 11000 bytes length at 0x8000000.
15:01:45.9041 [DEBUG] sysbus: Segment loaded.
15:01:45.9048 [INFO] sysbus: Loading segment of 360 bytes length at 0x8002AF8.
15:01:45.9049 [DEBUG] sysbus: Segment loaded.
15:01:45.9050 [INFO] sysbus: Loading segment of 256 bytes length at 0x2001F700.
15:01:45.9050 [DEBUG] sysbus: Segment loaded.
(machine-0) machine StartGdbServer 3333
15:02:58.5980 [INFO] machine-0: GDB server with all CPUs started on port :3333

Renode 側は問題なく、環境の設定が完了しました。v1.15 に比べて、ログの量が多いですね。それでは、GDB で接続していきます。

$ arm-none-eabi-gdb stm32f4discovery_sample.elf
(gdb) target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) monitor start
Starting emulation...
(gdb) disp/5i $pc
2: x/5i $pc
=> 0x0:    movs    r0, r0
   0x2: movs    r0, r0
   0x4: movs    r0, r0
   0x6: movs    r0, r0
   0x8: movs    r0, r0
(gdb) si
Reset_Handler () at ../startup.S:120
120            ldr     r1,  =__process_stack_start
2: x/5i $pc
=> 0x8000cf8 <Reset_Handler+4>: ldr r1, [pc, #24]  @ (0x8000d14 <Reset_Handler+32>)
   0x8000cfa <Reset_Handler+6>:  orr.w   r0, r0, #2
   0x8000cfe <Reset_Handler+10>: ldr r2, [pc, #24]  @ (0x8000d18 <Reset_Handler+36>)
   0x8000d00 <Reset_Handler+12>: bic.w   r0, r0, #1
   0x8000d04 <Reset_Handler+16>: msr PSP, r1

以下のように、Renode側に、いくつか気になる警告が出ましたが、うまく動いてるようです。

15:04:28.9269 [WARNING] sysbus: Tried to access bytes at non-existing peripheral in range <0x00000000, 0x00000003>.
15:05:48.8649 [INFO] cpu: Guessing VectorTableOffset value to be 0x8000000.
15:05:48.8711 [INFO] cpu: Setting initial values: PC = 0x8000CF5, SP = 0x20020000.
15:05:48.8742 [INFO] machine-0: Machine started.
15:06:46.4515 [WARNING] sysbus: Tried to access bytes at non-existing peripheral in range <0x00000000, 0x0000003F>.
15:07:05.7112 [WARNING] sysbus: Tried to access bytes at non-existing peripheral in range <0x00000000, 0x00000003>.

Renodeのv1.9でバイナリファイルから構築したELFファイルを動かす

では、ELFファイルから一度バイナリファイルに変換し、ELFファイルを再構築したデバッグ情報の無い ELFファイルを使って、やってみます。

$ ./renode
Gtk-Message: 15:11:18.480: Failed to load module "canberra-gtk-module"
15:11:22.8243 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.9.0+20200310git169a3c8_portable/./scripts/monitor.py
(monitor) mach create
15:13:42.4421 [INFO] System bus created.
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl
15:14:11.7848 [DEBUG] Segment size automatically calculated to value 16MiB
15:14:11.7864 [DEBUG] Segment size automatically calculated to value 64KiB
15:14:11.7865 [DEBUG] Segment size automatically calculated to value 128KiB
15:14:11.9750 [DEBUG] Segment size automatically calculated to value 64KiB
15:14:12.0839 [INFO] Reading cache
15:14:12.5026 [INFO] sysbus: Loaded SVD: /tmp/renode-18250/d3583bb6-5906-45ac-a48b-5fb2304666ac.tmp. Name: STM32F40x. Description: STM32F40x.
(machine-0) sysbus LoadELF @stm32f4discovery_sample_bin2elf_entry.elf
15:16:06.2839 [DEBUG] sysbus: Loading ELF /home/daisuke/svn_/renode/renode_1.9.0+20200310git169a3c8_portable/stm32f4discovery_sample_bin2elf_entry.elf.
15:16:06.2928 [INFO] sysbus: Loading segment of 11116 bytes length at 0x8000000.
15:16:06.3079 [DEBUG] sysbus: Segment loaded.
(machine-0) machine StartGdbServer 3333
15:18:30.7201 [INFO] machine-0: GDB server with all CPUs started on port :3333

Renode 側の起動は問題なく完了しました。GDB を接続していきます。

$ arm-none-eabi-gdb stm32f4discovery_sample_bin2elf_entry.elf
Reading symbols from stm32f4discovery_sample_bin2elf_entry.elf...
(No debugging symbols found in stm32f4discovery_sample_bin2elf_entry.elf)
(gdb) target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) monitor start
Starting emulation...

GDB 側からエミュレーションを開始できましたが、Renode 側で、以下のようなエラーが出ました。v1.15 で出ていたエラーと同じようです。

15:23:03.4246 [WARNING] sysbus: Tried to access bytes at non-existing peripheral in range <0x00000000, 0x00000003>.
15:23:13.2655 [WARNING] sysbus: ReadDoubleWord from non existing peripheral at 0x4.
15:23:13.2656 [WARNING] sysbus: ReadDoubleWord from non existing peripheral at 0x0.
15:23:13.2694 [ERROR] cpu: PC does not lay in memory or PC and SP are equal to zero. CPU was halted.
15:23:13.2695 [INFO] cpu: Setting initial values: PC = 0x0, SP = 0x0.
15:23:13.2700 [WARNING] cpu: Patching PC 0x0 for Thumb mode.
15:23:13.2732 [INFO] machine-0: Machine started.

この後、ステップ実行してみましたが、うまく動きませんでした。

Renodeのv1.9でバイナリファイルを動かす

バイナリファイルでやってみます。

$ ./renode
Gtk-Message: 16:15:09.517: Failed to load module "canberra-gtk-module"
16:15:13.8605 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.9.0+20200310git169a3c8_portable/./scripts/monitor.py
(monitor) mach create
16:15:40.0008 [INFO] System bus created.
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl 
16:15:57.2579 [DEBUG] Segment size automatically calculated to value 16MiB
16:15:57.2597 [DEBUG] Segment size automatically calculated to value 64KiB
16:15:57.2599 [DEBUG] Segment size automatically calculated to value 128KiB
16:15:57.4515 [DEBUG] Segment size automatically calculated to value 64KiB
16:15:57.5902 [INFO] Reading cache
16:15:58.0103 [INFO] sysbus: Loaded SVD: /tmp/renode-18499/3817eaaf-f1d4-417c-8831-907a71459863.tmp. Name: STM32F40x. Description: STM32F40x.
(machine-0) sysbus LoadBinary @stm32f4discovery_sample_objcopy.bin 0x08000000
16:18:08.6728 [DEBUG] sysbus: Loading binary /home/daisuke/svn_/renode/renode_1.9.0+20200310git169a3c8_portable/stm32f4discovery_sample_objcopy.bin at 0x8000000.
16:18:08.6902 [DEBUG] sysbus: Binary loaded.
(machine-0) machine StartGdbServer 3333
16:19:43.6066 [INFO] machine-0: GDB server with all CPUs started on port :3333

v1.15 では、LoadBinary を実行したとき、何もログが出力されなかったですが、v1.9 では、それらしいログが出ています。それでは、GDB を起動していきます。

$ arm-none-eabi-gdb stm32f4discovery_sample.elf
(gdb) target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) monitor start
Starting emulation...

GDB 側は正常に見えますが、Renode 側で以下のようなエラーが出ています。

16:20:26.1322 [WARNING] sysbus: Tried to access bytes at non-existing peripheral in range <0x00000000, 0x00000003>.
16:20:33.3925 [WARNING] sysbus: ReadDoubleWord from non existing peripheral at 0x4.
16:20:33.3925 [WARNING] sysbus: ReadDoubleWord from non existing peripheral at 0x0.
16:20:33.3945 [ERROR] cpu: PC does not lay in memory or PC and SP are equal to zero. CPU was halted.
16:20:33.3946 [INFO] cpu: Setting initial values: PC = 0x0, SP = 0x0.
16:20:33.3948 [WARNING] cpu: Patching PC 0x0 for Thumb mode.
16:20:33.3976 [INFO] machine-0: Machine started.

良さそうな感じに見えましたが、結果としては同じですね。

v1.9 で動かしてみましたが、v1.15 と結果は変わりませんでした。

v1.15のRenodeでデバッグログを出す

v1.15 に戻して、もう少し試します。

まず、普通に起動すると、Renode モニターという別のウィンドウが立ち上がりますが、--console オプションを付けて起動すると、同じウィンドウで操作が可能です。今後は、このオプションを使っていきます。

$ ./renode --console
Gtk-Message: 17:09:50.311: Failed to load module "canberra-gtk-module"
17:09:51.1583 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.15.0_portable/scripts/monitor.py
Renode, version 1.15.0.27975 (9111b18e-202403181532)

次に、現在のログレベルを確認して、ログレベルを変更してみます。

ログレベルは、Renode のログに関するドキュメント によると、以下の5種類があるようです。

  • NOISY:-1
  • DEBUG:0
  • INFO:1
  • WARNING:2
  • ERROR:3
(monitor) logLevel 
Currently set levels:
Backend           | Emulation element                   | Level
=================================================================
memory            :                                     : INFO
-----------------------------------------------------------------
console           :                                     : INFO
-----------------------------------------------------------------
(monitor) logLevel 0
(monitor) logLevel 
Currently set levels:
Backend           | Emulation element                   | Level
=================================================================
memory            :                                     : DEBUG
-----------------------------------------------------------------
console           :                                     : DEBUG
-----------------------------------------------------------------
(monitor) logLevel -1
(monitor) logLevel 
Currently set levels:
Backend           | Emulation element                   | Level
=================================================================
memory            :                                     : NOISY
-----------------------------------------------------------------
console           :                                     : NOISY
-----------------------------------------------------------------

デバッグログを入れて普通ののELFファイルを動かす

ログを最大で出力する設定でやってみます。ログの量が多いので、ログは重要なところだけ貼り付けます。まずは、普通の ELFファイルです。

(monitor) mach create
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl
(machine-0) sysbus LoadELF @stm32f4discovery_sample.elf 
17:32:50.9360 [DEBUG] sysbus: Loading ELF /home/daisuke/svn_/renode/renode_1.15.0_portable/stm32f4discovery_sample.elf.
17:32:50.9462 [INFO] sysbus: Loading segment of 11000 bytes length at 0x8000000.
17:32:50.9505 [NOISY] flash: Allocating segment of size 131072.
17:32:50.9506 [NOISY] flash: Segment no 0 allocated at 0x7755F1CB5780 (aligned to 0x7755F1CB6000).
17:32:50.9519 [NOISY] flash: Invalidating memory fragment at 0x0 of size 11000 bytes.
17:32:50.9687 [DEBUG] sysbus: Segment loaded.
17:32:50.9688 [INFO] sysbus: Loading segment of 360 bytes length at 0x8002AF8.
17:32:50.9688 [NOISY] flash: Invalidating memory fragment at 0x2AF8 of size 360 bytes.
17:32:50.9689 [DEBUG] sysbus: Segment loaded.
17:32:50.9690 [INFO] sysbus: Loading segment of 256 bytes length at 0x2001F700.
17:32:50.9691 [NOISY] sram: Allocating segment of size 65536.
17:32:50.9691 [NOISY] sram: Segment no 1 allocated at 0x7755F1D0CEA0 (aligned to 0x7755F1D0D000).
17:32:50.9692 [NOISY] sram: Invalidating memory fragment at 0x1F700 of size 256 bytes.
17:32:50.9693 [DEBUG] sysbus: Segment loaded.
(machine-0) machine StartGdbServer 3333
(machine-0) 17:33:40.5324 [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

Renode 側のログです。

(machine-0) 17:33:50.0886 [NOISY] machine-0: Starting sysbus.cpu.
17:33:50.0898 [INFO] cpu: Guessing VectorTableOffset value to be 0x8000000.
17:33:50.0919 [NOISY] cpu: VectorTableOffset set to 0x8000000.
17:33:50.0970 [INFO] cpu: Setting initial values: PC = 0x8000CF5, SP = 0x20020000.
17:33:50.0984 [NOISY] cpu: Resumed.
17:33:50.0985 [INFO] machine-0: Machine started.
17:33:50.1025 [NOISY] cpu: Waiting for a step instruction (PC=0x08000CF4).
17:33:50.2784 [NOISY] cpu: Trying to find the mapping for offset 0x8000C00.
17:33:50.2854 [NOISY] cpu: Allocated 24B pointer at 0x131210647451808.
17:33:50.2856 [NOISY] cpu: Allocated is now 40.45MiB.
17:33:50.3150 [NOISY] cpu: Allocated 48B pointer at 0x131210647877840.
17:33:50.3151 [NOISY] cpu: Allocated is now 40.45MiB.
17:33:50.3152 [NOISY] cpu: Allocated 24B pointer at 0x131210647837728.
17:33:50.3153 [NOISY] cpu: Allocated is now 40.45MiB.
17:33:50.3153 [NOISY] cpu: Allocated 24B pointer at 0x131211251178080.
17:33:50.3154 [NOISY] cpu: Allocated is now 40.45MiB.
17:33:50.3155 [NOISY] cpu: Allocated 24B pointer at 0x131211251178112.
17:33:50.3156 [NOISY] cpu: Allocated is now 40.45MiB.
17:33:50.3159 [NOISY] cpu: Deallocated a 24B pointer at 0x131210647451808.
17:33:50.3160 [NOISY] cpu: Memory mappings rebuilt, there are 1 host blocks now.

デバッグログをバイナリファイルから構築したELFファイルを動かす

続いて、バイナリファイルから構築した ELFファイルです。

$ ./renode --console
Gtk-Message: 17:09:50.311: Failed to load module "canberra-gtk-module"
17:09:51.1583 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.15.0_portable/scripts/monitor.py
Renode, version 1.15.0.27975 (9111b18e-202403181532)
(monitor) mach create
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl
(machine-0) sysbus LoadELF @stm32f4discovery_sample_bin2elf_entry.elf 
17:51:43.6156 [DEBUG] sysbus: Loading ELF /home/daisuke/svn_/renode/renode_1.15.0_portable/stm32f4discovery_sample_bin2elf_entry.elf.
17:51:43.6229 [INFO] sysbus: Loading segment of 11116 bytes length at 0x8000000.
17:51:43.6267 [NOISY] flash: Allocating segment of size 131072.
17:51:43.6268 [NOISY] flash: Segment no 0 allocated at 0x7F4675CC03B0 (aligned to 0x7F4675CC1000).
17:51:43.6279 [NOISY] flash: Invalidating memory fragment at 0x0 of size 11116 bytes.
17:51:43.6440 [DEBUG] sysbus: Segment loaded.
(machine-0) machine StartGdbServer 3333
17:55:22.6905 [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
0x00000000 in ?? ()

Renode 側のログです。

(machine-0) 17:55:51.3930 [NOISY] machine-0: Starting sysbus.cpu.
17:55:51.4016 [WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x4.
17:55:51.4018 [WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x0.
17:55:51.4051 [ERROR] cpu: PC does not lay in memory or PC and SP are equal to zero. CPU was halted.
17:55:51.4187 [INFO] cpu: Setting initial values: PC = 0x0, SP = 0x0.
17:55:51.4190 [WARNING] cpu: Patching PC 0x0 for Thumb mode.
17:55:51.4200 [NOISY] cpu: Resumed.
17:55:51.4201 [INFO] machine-0: Machine started.

デバッグログを入れてバイナリファイルを動かす

続いて、バイナリファイルです。

$ ./renode --console
Gtk-Message: 17:09:50.311: Failed to load module "canberra-gtk-module"
17:09:51.1583 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode_1.15.0_portable/scripts/monitor.py
Renode, version 1.15.0.27975 (9111b18e-202403181532)
(monitor) mach create
(machine-0) machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl
(machine-0) sysbus LoadBinary @stm32f4discovery_sample_objcopy.bin 0x08000000
17:27:45.2367 [NOISY] flash: Allocating segment of size 131072.
17:27:45.2368 [NOISY] flash: Segment no 0 allocated at 0x744C65D4A240 (aligned to 0x744C65D4B000).
17:27:45.2381 [NOISY] flash: Invalidating memory fragment at 0x0 of size 11116 bytes.
17:27:45.2580 [DEBUG] sysbus: /home/daisuke/svn_/renode/renode_1.15.0_portable/stm32f4discovery_sample_objcopy.bin File loaded.
(machine-0) machine StartGdbServer 3333
(machine-0) m17:28:11.9358 [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
0x00000000 in ?? ()

Renode 側のログです。

(machine-0) 17:28:23.2001 [NOISY] machine-0: Starting sysbus.cpu.
17:28:23.2095 [WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x4.
17:28:23.2096 [WARNING] sysbus: [cpu: 0x0] ReadDoubleWord from non existing peripheral at 0x0.
17:28:23.2127 [ERROR] cpu: PC does not lay in memory or PC and SP are equal to zero. CPU was halted.
17:28:23.2224 [INFO] cpu: Setting initial values: PC = 0x0, SP = 0x0.
17:28:23.2227 [WARNING] cpu: Patching PC 0x0 for Thumb mode.
17:28:23.2238 [NOISY] cpu: Resumed.
17:28:23.2239 [INFO] machine-0: Machine started.

ログを出してみましたが、大した情報は得られませんでした。

おわりに

今回は、バイナリファイルが動作しない原因を解析してみましたが、大した情報は得られませんでした。

次回は、Renode をソースからビルドして、Renode のソースを見ていこうと思います。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。