Renode という QEMU に似たオープンソースのエミュレータを試しています。
前回 は、バイナリファイルから構築した ELFファイルが動かない原因を解析して、対策を行い、無事に動作するところまで行いました。
今回は、VSCode でデバッグする環境を構築していきます。
それでは、やっていきます。
はじめに
「QEMUを動かす」の記事一覧です。良かったら参考にしてください。
QEMUを動かすの記事一覧
まず、Renode の公式サイトは以下です。
https://renode.io/
Renode の公式のドキュメントは以下です。
https://renode.readthedocs.io/en/latest/
また、GitHub は以下です。
https://github.com/renode/renode
今回は、Renode をソースからビルドします。
Renodeで普通のELFファイルをVSCodeでデバッグする
Renodeの公式ドキュメントのVSCodeでデバッグ のところに従って、やっていきます。
まずは、VSCode を起動して、リモートエクスプローラで、VirtualBox の Ubuntu 22.04 に SSH で接続します。
VSCode で リモートデバッグする方法は、以下の記事で詳しく書いたので、良かったら参考にしてください。
daisuke20240310.hatenablog.com
今は、ソースからビルドしたディレクトリで、Renode を動かしていますので、VSCode で、Renode をクローンしたディレクトリを開きます。
クローンしたソースツリーに、.vscode ディレクトリが既に用意されていて、.vscode/launch.json も入っています。ただし、この launch.json に設定されている内容は、ユーザのアプリケーションではなく、Renode 自体をデバッグするときの設定のようです。
ですので、launch.json に、ユーザアプリケーション用の設定を追加すればいいだけです。以下は、launch.json のユーザアプリケーション用の設定部分のみであり、公式ドキュメントに書かれているものを少し変更したものです。変更点は次の通りです。
- preLaunchTask を削除:デバッグ実行前に行う処理を登録できる設定で、ビルドするタスクと Renode を起動するタスクが登録されています(タスクは tasks.json に定義されています) → まずは手動で実行したいので削除しました
- postDebugTask を削除:デバッグ実行終了時に行う処理を登録できる設定で、デバッグセッションを終了させるタスクが登録されています(とドキュメントに書かれています) → こちらも、まずは手動でやります
- stopAtConnect を追加:true に設定すると、停止させた状態で、デバッグを開始させることができます(stopAtEntryもあるがアセンブラの場合はstopAtConnectじゃないと止まりませんでした)
- miDebuggerPath:GDB のパスを設定します
- program:実行ファイルのパスを指定します
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug application in Renode",
"type": "cppdbg",
"request": "launch",
"miDebuggerServerAddress": "localhost:3333",
"stopAtConnect": true,
"cwd": "${workspaceRoot}",
"miDebuggerPath": "arm-none-eabi-gdb",
"program": "${workspaceRoot}/stm32f4discovery_sample.elf"
},
]
}
VSCode の設定が出来たので、早速デバッグしていきます。
これまで、Renode を起動した後、いくつかの設定を手動で入力していましたが、今回から、スクリプト(rescファイル)に書いて、それを使っていきます。
参考にした rescファイルは、Renodeを最初に試したときの記事でも、参考にさせてもらったGitHubの https://github.com/memfault/interrupt/blob/master/example/renode/renode-config.resc です。
いつも手動で入力していた内容を書いてあるだけです。
name: STM32F4 Discovery Printf
description: This script runs the usart_printf example on stm32f4 discovery
$name?="STM32F4_Discovery"
$bin?=@stm32f4discovery_sample.elf
mach create $name
machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl
machine LoadPlatformDescription @add-ccm.repl
machine StartGdbServer 3333
macro reset
"""
sysbus LoadELF $bin
"""
runMacro $reset
それでは、Renode を起動していきます。VSCode の ターミナル→新しいターミナルをクリックします。
すると、Renode をクローンしたディレクトリで、シェルが起動するので、いつも通りに Renode を起動します。rescファイルを読み込んで使用するには、i rescファイルパス で使うことが出来ます。
$ ./renode --console
(Renode:6772): Gdk-CRITICAL **: 20:17:15.682: IA__gdk_keymap_get_for_display: assertion 'GDK_IS_DISPLAY (display)' failed
20:17:16.4212 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode/scripts/monitor.py
Renode, version 1.15.0.37629 (f830e634-202406021825)
(monitor) i @renode-config.resc
20:17:19.3840 [INFO] Including script: /home/daisuke/svn_/renode/renode/renode-config.resc
20:17:19.4078 [INFO] System bus created.
20:17:21.2113 [INFO] sysbus: Loaded SVD: /tmp/renode-6772/8d073280-bb50-46b3-8190-0f4c4177a56d.tmp. Name: STM32F40x. Description: STM32F40x.
20:17:21.2908 [INFO] STM32F4_Discovery: GDB server with all CPUs started on port :3333
20:17:21.3178 [INFO] sysbus: Loading segment of 11000 bytes length at 0x8000000.
20:17:21.3386 [INFO] sysbus: Loading segment of 360 bytes length at 0x8002AF8.
20:17:21.3392 [INFO] sysbus: Loading segment of 256 bytes length at 0x2001F700.
(STM32F4_Discovery)
いつもは、ここで GDB を起動していましたが、代わりに、VSCode のデバッガ(実際はいつものGDBです)を起動していきます。実行とデバッグのメニューから Debug application in Renode を選んでデバッガを起動します。
Renode 側のデバッガ起動後のログです。
20:17:29.6863 [INFO] cpu: *** vtorInitialized=False, firstNotNullSection.HasValue=True ***
20:17:29.6864 [INFO] cpu: Guessing VectorTableOffset value to be 0x8000000.
20:17:29.6881 [INFO] cpu: *** pcNotInitialized=True, VectorTableOffset=134217728 ***
20:17:29.6918 [INFO] cpu: Setting initial values: PC = 0x8000CF5, SP = 0x20020000.
20:17:29.6936 [INFO] STM32F4_Discovery: Machine started.
以下のように、startup.S の先頭で停止しました。
VSCodeでデバッグ画面が表示された
ソースパスを指定した覚えは無いですが、なぜか、ソースが表示されてますね。
いつも通り、ステップ実行や、ブレークポイントを設定するなどもできて、正しく動作しているようです。
ソースコードのウィンドウで右クリックして、「逆アセンブリビューを開く」をクリックすると、アセンブラが表示されて、アセンブラの命令を一つずつステップ実行することも出来ました。ただし、Eclipse のように、アセンブラ側でステップ実行すると、Cソース側も同期して、どこを実行しているか分かりますが、その機能は無いようです。
逆アセンブリビューを開いたところ
Renodeでバイナリファイルから構築したELFファイルをVSCodeでデバッグする
続いて、デバッグ情報の無い ELFファイルを、VSCodeでデバッグしてみます。
.vscode/launch.json の "program": "${workspaceRoot}/stm32f4discovery_sample.elf" を、"program": "${workspaceRoot}/stm32f4discovery_sample_bin2elf.elf " に変更します。
また、renode-config.resc の $bin?=@stm32f4discovery_sample.elf を $bin?=@stm32f4discovery_sample_bin2elf.elf に変更します。
それでは、Renode を起動します。
$ ./renode --console
(Renode:10538): Gdk-CRITICAL **: 21:58:25.438: IA__gdk_keymap_get_for_display: assertion 'GDK_IS_DISPLAY (display)' failed
21:58:26.2345 [INFO] Loaded monitor commands from: /home/daisuke/svn_/renode/renode/scripts/monitor.py
Renode, version 1.15.0.39127 (f830e634-202406021825)
(monitor) i @renode-config.resc
21:58:27.8745 [INFO] Including script: /home/daisuke/svn_/renode/renode/renode-config.resc
21:58:27.9009 [INFO] System bus created.
21:58:29.9635 [INFO] sysbus: Loaded SVD: /tmp/renode-10538/c22b0a54-2252-4eec-9019-e5bd1f6e3e18.tmp. Name: STM32F40x. Description: STM32F40x.
21:58:30.0498 [INFO] STM32F4_Discovery: GDB server with all CPUs started on port :3333
21:58:30.0740 [INFO] sysbus: Loading segment of 11116 bytes length at 0x8000000.
(STM32F4_Discovery)
特に問題はなさそうなので、デバッガを起動します。以下は、デバッガ起動後のログです。
21:58:36.3178 [INFO] cpu: *** vtorInitialized=False, firstNotNullSection.HasValue=True ***
21:58:36.3179 [INFO] cpu: Guessing VectorTableOffset value to be 0x8000000.
21:58:36.3202 [INFO] cpu: *** pcNotInitialized=True, VectorTableOffset=134217728 ***
21:58:36.3242 [INFO] cpu: Setting initial values: PC = 0x8000CF5, SP = 0x20020000.
21:58:36.3257 [INFO] STM32F4_Discovery: Machine started.
ソースはもちろん表示されませんし、逆アセンブリビューにも何も表示されません。デバッグコンソールの方を見て、適当に si とか入力してみたりしましたが、何もできません。困りました。
ふと、画面左下の不明なソースをダブルクリックしてみると、逆アセンブリビューにコードが表示されて、ステップ実行も問題なく出来ました。
画面の左下の不明なソースをダブルクリックしたら逆アセンブリビューにコードが表示された
これは分かりにくかったです。ブレークポイントを設定して、続行をクリックしてみると、正しくブレークポイントで停止しました。正しく動作しているようです。
おわりに
今回は、Renode で、VSCode を使ってデバッグしてみました。GDB でデバッグするより、ずっと楽ですね。
次回は、Renode 自体を VSCode でデバッグしてみようと思います。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。