動的解析をスタンドアロンで使用
C-RUNはIAR Embedded Workbenchのアドオンとして使用する動的解析ツールです。C-RUNはオーバーフローや境界エラーまたはメモリの誤った使用などを検出することが可能です。通常は統合開発環境およびICEを使用して、検出結果を確認しますが、本稿でご紹介する方法によりスタンドアロンでも使用可能です。
C-RUNのエラーメッセージは、通常デバッグウィンドウに表示され、また任意のウィンドウにリダイレクトすることができます。そして、そのメッセージを保存し、後で確認することも可能です。
ターミナルI/Oに動的解析の出力をリダイレクト
C-RUNのメッセージはセミホスティングによりPCに転送されます。C-RUNのメッセージは<EWARM>\arm\src\lib\crunに実装があります。スタンドアロンでC-RUNを動作させる前に、ターミナルI/Oを試してみましょう。
ワークスペースにReportCheckFailedStdout.cを追加
先述の\crunフォルダにあるReportCheckFailedStdout.cをワークスペースにコピーします。
ファイルは読み取り専用モードになっていますのでプロパティを変更しましょう。
C-RUNメッセージをリダイレクト
C-RUNエラーメッセージをリダイレクトするためにリンカの設定を変更しましょう。デフォルトでは、__iar_ReportCheckFailedisが呼ばれます。これを、ReportCheckFailedStdout.cで実装されている__iar_ReportCheckFailedStdoutにします。
__interwork void __iar_ReportCheckFailedStdout(void * d)
{
char buf[200] = {0};
char *b = buf;
uint32_t const *data = (uint32_t const *)d;
int nr = data[0] >> 24;
b = putstring(b, "CRUN_ERROR:");
for (int i = 0; i < nr; ++i)
{
*b++ = ' ';
b = puthex(b, data[i]);
}
*b++ = '\n';
__write(_LLIO_STDOUT, (unsigned char const *)buf, (size_t)(b - buf));
if (__iar_ReportCheckFailedStdoutAbort)
abort();
}
リンカのオプションから、以下のように追加オプションを指定します。
--redirect __iar_ReportCheckFailed=__iar_ReportCheckFailedStdout
C-RUNによるデバッグ
デバッグを開始する前に、C-RUNで検出したい問題を指定できているか確認してください。その後、すべてを再ビルドし、ダウンロードしてデバッグを開始しましょう。表示 > ターミナルIOによりウィンドウを開きます。
C-RUNがエラーメッセージを検出したら、ターミナルIOに出力されます。
これによりターミナルIO上でC-RUNのメッセージが確認できるようになりました。出力は生データで、cspybat.exeを使用するとメッセージが見えます。
C-RUNの生データをcspybat.exeで見やすく
cspybat.exeは、デバッグのバッチを制御するツールですが、C-RUNの生データを見やすく整形するのにも使用できます。
バッチファイルを修正
プロジェクトをビルドするたび、***.cspy.batというファイルが生成されます。エディタでそのファイルを開いてみましょう。--rtc_enableの後に--rtc_filterを追加して、ファイルを保存してください。
コマンドプロンプトからバッチを実行
コマンドプロンプトを開き、プロジェクトの\settingsフォルダに移動します。そして、バッチファイルを指定、
さらに出力ファイルのパスを追加します。
この例では、c.outを単純化のために移動しておきました。もちろん、絶対パスによる指定も可能です。
これでcspybatがC-RUNの生データを待っている状況になりました。
生データを整形
ターミナルIOで取得したメッセージを整形してみましょう。メッセージは1行で出力すべきということに注意してください。
Enterを押すと、以下のように整形されたメッセージが表示されます。
整数の型変換に失敗していて、それがmain.cの16行目であることがわかります。C-RUNをデフォルトで使った場合に、C-RUNのメッセージウィンドウに出力されるものと同様です。
注意:C-RUNの生データにはコールスタックが含まれません
C-RUNのメッセージをUARTにリダイレクト
C-RUNのメッセージは他の通信チャネルにももちろんリダイレクト可能です。この場合、単純に、_iar_ReportCheckFailedStdout関数を変更します。
_iar_ReportCheckFailedStdout関数の変更
ReportCheckFailedStdout.cを開きます。
__interwork void __iar_ReportCheckFailedStdout(void * d)
{
char buf[200] = {0};
char *b = buf;
uint32_t const *data = (uint32_t const *)d;
int nr = data[0] >> 24;
b = putstring(b, "CRUN_ERROR:");
for (int i = 0; i < nr; ++i)
{
*b++ = ' ';
b = puthex(b, data[i]);
}
*b++ = '\n';
__write(_LLIO_STDOUT, (unsigned char const *)buf, (size_t)(b - buf));
if (__iar_ReportCheckFailedStdoutAbort)
abort();
}
ローカル変数bufにC-RUNのメッセージが含まれます。メッセージは、__write関数により送られます。__write関数をコメントアウトし、代わりにser_printf関数の呼び出しにしてみましょう。
ser_printf関数は他のファイルで定義されています。またUARTはC-RUNがメッセージを送る前にセットアップする必要があります。
同様にして、SPIやI2CまたはRAMやFlashへのリダイレクトも可能です。
ターミナルを開いて、プロジェクトを実行
Tera Termなどターミナル・アプリケーションを開き、ダウンロードしてデバッグを開始しましょう。
Tera TermにC-RUNのエラーメッセージが出力されるようになります。一文字目のAはアプリケーションからの出力です。
スタンドアロンで実行
ICEをボードからはずし、再度ボードの電源を入れてみましょう。ボード単体でC-RUNのメッセージがターミナルに出力されるはずです。
以上で、ICEなしのフィールドテストにおいて、C-RUNのメッセージが収集できるようになりました。集めたメッセージは、前述のとおり、cspybat.exeによって、整形することができます。
注意: バッチファイルを生成するとき、デバッガ > ダウンロード > フラッシュローダを使用する(U) チェックボックスをはずしてください。
まとめ
C-RUNは手軽で便利な動的解析のアドオンです。本稿でご紹介した方法により、スタンドアロンのテストでぜひご活用ください。