・現在、SH3(SH7709S)を使ったシステムで、数か月に1回、不定期にCPUの例外処理が発生しています。
例外が発生した場合 spc等の情報をログに残すようにしています。その情報をもとに
原因や例外の発生場所を探しているのですが、メモリダンプして下記SPCのアドレスを検索しても
ヒットしません。(メモリマップ上に存在しないアドレスのため)
・このあと、どのように調査や対策をしたらよいのか途方に暮れている状況です。
どなたか少しでも参考になる方法がありましたら教えて下さい。
(例外は工場現場でしか発生しないため、デバッガを接続して調査することができません)
(メモリマップ)
ROM(FMEM) 0000_0000~0007_FFFF
SRAM 0C00_0000~0C0F_FFFF
(例外事例)
spc=3A5D3869,ssr=0100,evnt=00E0 (命令アドレスエラー)
spc=07070707,ssr=0101,evnt=00E0(命令アドレスエラー)
spc=06060870,ssr=0100,evnt=0180(一般不当命令)
(参考)
ソースコードの解析ではスタックや配列のオーバーフローが起きそうな箇所は見つかりませんでした。
各種測定器でノイズを測るとほかの正常なシステムと同等レベルでした。
他に必要な情報がありましたらご連絡ください。
バッファオーバーランで関数からの戻り番地をぶっ壊してどっか変なところ飛んでるか、スタックオーバーフローでスタックポインタが変なところ指した状態で関数呼び出しをして復帰に失敗してどっか変なところ飛んでるか、RAM上に配置した関数テーブルをバッファオーバーランかなんかでぶっ壊した結果変なところ飛んでるか、関数テーブルを範囲外で参照してしまいどっか変なところ飛んでる辺りがこの手の問題ではありがちですね。
> ソースコードの解析ではスタックや配列のオーバーフローが起きそうな箇所は見つかりませんでした。
見つかりませんでした=絶対に問題はありません ではない筈で問題の原因は疑われた箇所にある可能性は高いと思います。
> SH3(SH7709S)のCPU例外発生時に、例外発生場所の特定の方法を教えてください。
例外発生場所は特定できてるのでは?
> (例外事例) > spc=3A5D3869,ssr=0100,evnt=00E0 (命令アドレスエラー) > spc=07070707,ssr=0101,evnt=00E0(命令アドレスエラー) > spc=06060870,ssr=0100,evnt=0180(一般不当命令)
特定されたいのは例外が発生しているおかしなアドレスにどこの関数から飛んでいってるかではないでしょうか?
貴重なアドバイスありがとうございます。
・オーバーフロー等の可能性のあるソースコードに、オーバーフローしないよう条件文を追加することとしました。
すでに条件文は実装されていますが見落としがあるかもしれませんので、総点検中です。
・例外発生時にSPCを保存していますが、どこの関数から飛んできたかがわからないため、バグの発見がいまだにできない状況です。例外時にどこの関数から飛んできたかある程度推定できる方法がありましたら、アドバイスいただけないでしょうか?
(現場で不定期にしか発生しないため、残念ながらデバッガが使えません)
よろしくお願いします。
> ・オーバーフロー等の可能性のあるソースコードに、オーバーフローしないよう条件文を追加することとしました。
問題の原因を突き止めて解決することが正解であり、現象が表れなくすることは原因の特定からは遠ざかる方向なので悪手ですね 。
机上で特定できない論理バグはそうあるものではないと思います。コードの見直しが重要です。可能であれば、開発者チーム外のメンバーによる見直しができれば問題の発見に役立つ可能性があります。同じチームの開発者による見直しであれば特定の勘違いや思い込みが盲点となっていることはあり得ます。
> ・例外発生時にSPCを保存していますが、どこの関数から飛んできたかがわからないため、バグの発見がいまだにできない状況です。例外時にどこの関数から飛んできたかある程度推定できる方法がありましたら、アドバイスいただけないでしょうか?
各関数の先頭や処理の途中途中で例外処理が発生した場合でも破壊されないRAMの領域に関数名や行番号を記録する命令を本来の処理の邪魔にならない程度に忍ばせておき、例外処理が発生した場合にそれら記録した内容を不揮発メモリやネットワークにダンプするコードを組み込めば、どこまで動作した後で例外処理が発生したかは判定することが可能となります。スタック領域の前後に番兵を置き、それが破壊されないことを監視することも有用でしょう。
外部業者も交えてコードの再点検中ですが、正直なところ新しいバグを見つける可能性は低いと考えています。ご提案のように、原因を突き止めることを重視して関数の実行ログを取る仕組みを導入することにしました。現場のバージョンアップとトラブル再発・原因を究明までは1年がかりとなりますが、結果がわかりましたら参考までに報告させていただきます。
ご協力ありがとうございます。
>各関数の先頭や処理の途中途中で例外処理が発生した場合でも破壊されないRAMの領域に関数名や行番号を記録する命令を本来の処理の邪魔にならない程度に忍ばせておき、例外処理が発生した場合にそれら記録した内容を不揮発メモリやネットワークにダンプするコードを組み込めば、どこまで動作した後で例外処理が発生したかは判定することが可能となります。スタック領域の前後に番兵を置き、それが破壊されないことを監視することも有用でしょう。
あと、ベクタベースレジスタにおかしな値を設定してしまったりベクタテーブルの内容が壊れた状態で割り込みを受け付けてしまうと思わぬ箇所への分岐となってしまう可能性があり、その場合は関数の実行ログも意味をなさなくなるので例外発生時にはベクタベースレジスタの値やベクタテーブルの内容はチェックされた方が良いですね。
例外処理中に、ベクタベースレジスタの値やベクタテーブルの内容をチェックする、という視点は抜けていました。実装して次回発生時に確認します。
現在、関数ログの実装を進めているところです。
ご回答ありがとうございます。