Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

土日の勉強ノート

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

STM32(ARM Cortex-M)のバイナリから構築したELFファイルをQEMUで動かす

前回は、QEMU (ターゲットは STM32F4-Discovery)で動かしたELFファイルをバイナリファイル(デバッグ情報、シンボル情報が削除される)に変換して、そのバイナリファイルでELFファイルを再構築しました。

今回は、そのELFファイル(デバッグ情報、シンボル情報なし)を QEMU で動かしていきたいと思います。

それでは、やっていきます。

参考文献

STM32F4 のマニュアル

STM32F4 のマニュアル

下記リンクのドキュメント→リファレンスマニュアル、ドキュメント→プログラミングマニュアルなどを参照してください。最近は、マニュアルが日本語化されていて、とても便利です。

デザイン/サポート | STM32, STM8ファミリはSTの32bit/8bit汎用マイクロコントローラ製品

GDBのマニュアル

英語ですごい量です。日本語マニュアルへのリンクもありましたが、少し古かったです。

GDB Documentation

はじめに

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

QEMUを動かすの記事一覧

それでは、やっていきます!

コマンドラインでQEMUを動かしてGDBでデバッグする

第1回第2回 で、QEMU を動かしたときは、Eclipse(総合開発環境:IDE) を使いました。

今回は、デバッグ情報、シンボル情報の無いバイナリファイルで動かすので、まずは、コマンドラインの GDB を使い、QEMU もコマンドラインで動かします。

デバッグ情報のある通常のELFファイルを使ってコマンドラインでQEMUとGDBを動かす

まずは、環境が正しいことを確認したいので、普通の ELFファイルを使います。

コマンドラインで、QEMU を起動します。基本的には、Interface 2022年 7月号 に書かれている通りですが、「-S(起動してすぐに停止する)」と「--image stm32f4discovery_sample.elf(ロードするELFファイル)」を追加しています。

$ qemu-system-gnuarmeclipse -S --verbose --board STM32F4-Discovery --mcu STM32F407VG --image stm32f4discovery_sample.elf --gdb tcp::1234 -d unimp,guest_errors --semihosting-config enable=on,target=native --semihosting-cmdline stm32f4discovery_sample

QEMU を起動したら、次は、GDB を実行します。

$ arm-none-eabi-gdb stm32f4discovery_sample.elf 
(gdb) target remote :1234

これで GDB側からデバッグが出来ます。今回は、確認なので、c(継続実行)を入力して、LED が点滅していること(と LED のログ出力)を確認して、終了します。

通常のELFファイルでQEMUを起動する
通常のELFファイルでQEMUを起動する

単純にobjcopyで作成したELFファイルでQEMUとGDBを動かす

まずは、前回 実施した以下のコマンドで、単純に objcopy で作成した ELFファイルを使います。

$ arm-none-eabi-objcopy -I binary -O elf32-little --change-section-address .data=0x08000000 stm32f4discovery_sample_objcopy.bin stm32f4discovery_sample_objcopy.elf

また、先ほどは、評価ボードの LED や、ボタンスイッチが表示されるように起動しましたが、今回は LED が点滅するだけでいいので、グラフィックは OFF(--nographic)にします。

$ qemu-system-gnuarmeclipse -S --nographic --verbose --board STM32F4-Discovery --mcu STM32F407VG --image stm32f4discovery_sample.elf --gdb tcp::1234 -d unimp,guest_errors --semihosting-config enable=on,target=native --semihosting-cmdline stm32f4discovery_sample

QEMU を起動したら、次は、GDB を実行します。

$ arm-none-eabi-gdb stm32f4discovery_sample.elf 
(gdb) target remote :1234

objcopyで作成したELFファイルをQEMUで動かす
objcopyで作成したELFファイルをQEMUで動かす

動きましたが、逆アセンブルが、Thumb命令を認識していないので、別の命令に見えています。LED が点滅しているログが表示されているので、動作としては正しいようです。

bin2elf.shで作成したELFファイルでQEMUとGDBを動かす

次は以下のように bin2elf.sh で、作成した ELFファイルを使います。

$ ./bin2elf.sh stm32f4discovery_sample_objcopy.bin stm32f4discovery_sample_bin2elf.elf 0x08000000

QEMU を起動します。

$ qemu-system-gnuarmeclipse -S --nographic --verbose --board STM32F4-Discovery --mcu STM32F407VG --image stm32f4discovery_sample_bin2elf.elf --gdb tcp::1234 -d unimp,guest_errors --semihosting-config enable=on,target=native --semihosting-cmdline stm32f4discovery_sample

QEMU を起動したら、次は、GDB を実行します。

$ arm-none-eabi-gdb stm32f4discovery_sample_bin2elf.elf 
(gdb) target remote :1234

bin2elf.shで作ったELFファイルでQEMUを動かす
bin2elf.shで作ったELFファイルでQEMUを動かす

今度は、逆アセンブルが、Thumb命令を認識していて、正しく表示されています。

bin2elf_entry.shで作成したELFファイルでQEMUとGDBを動かす

次は以下のように bin2elf_entry.sh で、作成した ELFファイルを使います。

$ ./bin2elf_entry.sh stm32f4discovery_sample_objcopy.bin stm32f4discovery_sample_bin2elf_entry.elf 0x08000000 0x8000cf5

QEMU を起動します。

$ qemu-system-gnuarmeclipse -S --nographic --verbose --board STM32F4-Discovery --mcu STM32F407VG --image stm32f4discovery_sample_bin2elf_entry.elf --gdb tcp::1234 -d unimp,guest_errors --semihosting-config enable=on,target=native --semihosting-cmdline stm32f4discovery_sample

QEMU を起動したら、次は、GDB を実行します。

$ arm-none-eabi-gdb stm32f4discovery_sample_bin2elf_entry.elf 
(gdb) target remote :1234

bin2elf_entry.shで作成したELFファイルでQEMUを動かす
bin2elf_entry.shで作成したELFファイルでQEMUを動かす

エントリポイントを設定した ELFファイルについても、逆アセンブルが、Thumb命令を認識していて、正しく表示されています。

Eclipseを使ってQEMUでバイナリから構築したELFファイルをデバッグする

コマンドラインの QEMU と GDB を使って動作させることが出来たので、Eclipse を使って、デバッグ情報の無い ELFファイルのデバッグをやってみます。

ELFファイルは、最後に使った、エントリポイントを設定した ELFファイルを使います。

新しくプロジェクトを作ります。

第1回で詳しく説明したので、ここでは、違うところだけを詳しく説明します。

daisuke20240310.hatenablog.com

「stm32f4discovery_sample」というプロジェクトを開いてる状態かもしれませんが、File→New→Projectをクリックします。

プロジェクトの作成と設定

C/C++のC Projectを選択してNextをクリックします。

Project name は、「stm32f4discovery_binary」として、Project type は「Empty Project」を選び、Toolchains は「Arm Cross GCC」を選択して、Next をクリックします。

何回か、Next を押すと、Finish が出るのでクリックします。

すると、複数のプロジェクトが見えている状態かもしれません。今回作成した「stm32f4discovery_binary」プロジェクト以外は閉じておきます(他のプロジェクトの影響がないようにと思って閉じることにしました)。

stm32f4discovery_sampleプロジェクトは閉じておく
stm32f4discovery_sampleプロジェクトは閉じておく

ソースは無い想定なので、インポートはせずに、プロジェクトの設定を行います。

Project→Properties を開きます。

C/C++ Build の Settings をクリックします。TargetProcessor をクリックして、Arm family を cortex-m4 を選択します。Float ABI は QEMU が FPU に対応していないため、Library (soft) を選択します。

ここまでは同じで、リンカスクリプトは無いので、指定しません。

GNU Arm Cross C Linker の Miscellaneous を開いて、右下の Other linker flags に、-specs=nosys.specs -specs=nano.specs -specs=rdimon.specs -lc -lrdimon と入力します。

ビルドしないので、Build Tools Path の入力は不要です。完了したら、Apply and Close をクリックします。

デバッグの設定

続いて、デバッグの設定です。

Run→Debug Configurations... をクリックします。

左の GDB QEMU Debuggin をダブルクリックします。すると、「stm32f4discovery_binary Debug」という項目がすぐ下に作られます。

Mainタブの C/C++ Application は、Browse... をクリックして、stm32f4discovery_sample_bin2elf_entry.elf を指定してください。

ビルドはしないので、Disable auto build にチェックを入れて、Apply をクリックします。

次は、Debugger タブです。

QEMU までのパスを指定して、Board name に「STM32F4-Discovery」を入力し、Device name に「STM32F407VG」を入力します(私の場合は全て入力済みでした)。

評価ボードのグラフィックは不要なので、Do not open graphic windows にチェックを入れておきます。

最後に GDB までのフルパスを指定して、Apply をクリックします。

Debuggerタブの設定
Debuggerタブの設定

あと、起動して、すぐに Run してほしくないので、Start タブの一番下にある Continue のチェックも外しておきます。

デバッグする

では、実際に動かしていきます。虫アイコンを押して、デバッグを開始します。

ソースコードが無いため、下のような画面になると思います。Preferences... をクリックします。

デバッグ起動画面
デバッグ起動画面

Source Not Found と書かれているところを、Never にチェックを入れて(先ほどのような画面が毎回出ると面倒なので)、Apply and Close をクリックします。

Window→Show View をクリックして、Disassembly、Debugger Console、Registers を開きます。このような画面になると思います。

デバッガ起動画面
デバッガ起動画面

Disassembly は、なぜか 0番地を表示していますが、PCレジスタを見ると、エントリポイント(0x08000cf4)にいます。

Debugger Console に「si」と入力してリターンします。一度、ステップ実行すると、正しく表示されます。

「si」と入力して、リターンするだけで、逆アセンブルとレジスタの値が見れるので、コマンドラインの GDB より楽ですね。ツールバーのステップイン実行や、ステップオーバーは使えないので注意です。

「c」とリターンを押すと、実行が始まって、LED が点滅するログが表示されます。正しく動作しているようです。

おわりに

今回は、デバッグ情報、シンボル情報がない ELFファイルを、GDB や Eclipse でデバッグしました。GDB は、非常に多くの機能があるので、いろいろ試してみたいと思います。

次回以降は、QEMU のソースコードを変更、ビルドして、QEMU の動きを変えてみたいと思います。

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

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

今回は以上です!

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