最近、STM32マイコン用のクラス・ライブラリを作っています。
もともとの動機は、STM32のHALを使うのがやや煩雑なのでこれを包み込んで使いやすくしようというものです。下回りはちゃんと地ならししておかないと、自分がほんとうに実装したいアルゴリズムに集中できなくなってしまいます。
そんなわけで、ここ数ヶ月ほどHALをつついたりしながら作業してきましたが、ここに来て漸く形が整ってきました。UART, I2C, SPIに関してスレッド・セーフかつブロッキングなIOが可能で、SPIに関してはスレーブ毎にチップ・セレクト・ピンとクロックの極性や位相を指定できます。これだけやれば、上の層を書くのも楽になるはずです。
さて、きちんとしたライブラリにはきちんとしたデバッグ機構が必要です。そこで、クラス・ライブラリのあちこちにアサーションを埋め込みました。そうなると、ポストモーテム・ダンプも欲しいところです。こういったいきさつで週の後半にかけてARM Thumbのバックトレース(ルーチンの呼び出し階層の表示)について調べていたわけです。
結論から言うと、時間の無駄でした。ARM Thumbでアプリケーションから手早くスタックのバックトレースを解析することはできません。
ARM社のThe ARM Thumb Procedure Call Standard (ATPCS)にはスタックのunwinding (スタックの巻き戻し。呼び出し履歴の解析に同じ)方法が書いていますが、正直言ってやってられるかという内容です。詳細は省きますが、FPが示すものが一定していませんし、そもそもATPCSではFPはオプションです。「ELFのデバッガ向け情報を参照しろ」とか「ルーチンエントリーコードを解析しろ」とか、ベアメタルでの実行時には不可能なことばかりです。
ネットで検索しても組み込み用のunwindingに関しては結論の出ない話ばかり。gccの__builtin_return_address()は自関数の戻り番地は返しますが、呼び出し元の戻り番地に関しては0を返します。さしものgcc開発者も匙を投げたのでしょう。
ATPCSを読むかぎり、昔々レジスタを節約するために考えたけちな技法がそのまま使われているのではないかと感じます。CORTEX-Mを設計するときに一旦ご破算にできたはずなのですが、その度胸が無かったのでしょう。結果的にそれまで蓄積され広く知られているFPを使ったテクニックは世界中のARMマイコンで使えないわけです。
ちょっとした地球規模の災害と言えます。