1. はじめに
デバッグ時、特に例外等が発生した時に役に立つのが、関数呼び出しの階層(call stack)表示機能です。Cortex-M系では実行時にcall stackの情報取得はできないと思っていました(下記リンク先参照)。
最近Arduno Uno R4について調べていたところ、以下のファアイルを見つけました。
C:\Users\%USERNAME%\AppData\Local\Arduino15\packages\arduino\hardware\renesas_uno\1.0.5\cores\arduino\cm_backtrace\cm_backtrace.c
オリジナルは、githubにありました。
CmBacktraceでは、どのようにcall stack情報を取得しているかを調べてみました。
2. CmBacktraceにおけるcall stack情報取得方法
ソースを調べたところ、以下の処理を行っていることがわかりました。
- 指定されたアドレス(SPの値)から、割り当てられたスタック領域の中で、最下位ビットが1になっているuint32_tの値を見つける。これはBL命令などを使ってThumb(T32)コードから関数を呼び出した時、LRには戻りアドレスの最下位ビットをセットした値が入るので、戻りアドレス値の候補となります。
- 戻りアドレスがコード領域に入っていることを確認する。
- 戻りアドレスの直前の命令が、関数呼び出しを行うBL命令あるいはBLX命令かをチェックする。もしそうであれば、それを順番に配列に格納する。
上記の処理はCortex-Mの関数呼び出し処理の性質を利用した方法なので、他のアーキテクチャでは利用できませんが、よく考えられていると感じました。
3. 最後に
このような方法でcall stackが取得できるんですね。機会があったら使ってみたいと思います。