バックナンバーはこちら

today&tomorrow

Technology Update

2018 vol.110

バーチャル・プロトタイプを使用した組込みソフトウェアのデバッグ

バーチャル・プロトタイプのソフトウェア・アサーションを使用したメモリー破損の検出

ソフトウェア開発者にとって非常に厄介なのは、カーネル・パニックの問題が散発的に発生する場合です。この問題は多くの場合非確定的で、特定のタイミングで発生するようには見えません。よくあるのは、プログラム・カウンタが無効なプログラム・アドレスに設定されてプリフェッチ・アボートがトリガーされる場合や、MMUによってマッピングされていないメモリーにアクセスしようとした場合です。このような場合、最初にデバッガとトレースによる解析を実行すると、不正な関数またはデータ・ポインタが根本原因であることがほとんどです。しかしスタックが破損して誤ったレジスタ(リターン・アドレス)にリンクされているという深刻なケースもあります。このように、メモリー内のデータが何らかの時点で破損することはしばしばあります。カーネルの重要なデータ構造であるにせよ単なる関数スタックであるにせよ、このような種類の不具合をその根本原因までトレースバックするのは悪夢のような作業です。

ここではMMU、キャッシュ、メモリー・マップが正しく設定され、基本的なカーネルが正しく動作しているものと仮定します(これらに問題がある場合はもっと早い段階で症状が現れるため、別のデバッグ・ストラテジで対処します)。この場合、カスタム・ドライバーなどの場所で一般に次のようなタイプのエラーが観察されます。

  • ヒープ・メモリーのエラー(メモリー・リーク)
  • 初期化されていないヒープ・データの読み出し
  • 割り当てられていないヒープ・メモリーへのアクセス(バッファ・オーバーランなど)。この結果、後で別の場所が上書きされてしまいます(図20参照)。

画像

図20:メモリー破損の原因と遅れて現れる症状

特にカーネル空間にこの種の問題が存在すると、ここを入口としてシステムが攻撃、改ざんされる可能性があります。こうしたバグの多くは、数百万人というエンド・ユーザーに販売されている機器のソフトウェア・スタックに潜んでいます。よくあるのは、ヌル終端文字列を別のバッファにコピーすることで発生するエラーです。多くの場合、バッファの割り当て時にヌル終端文字を想定していないため、バッファのサイズが不足してエラーとなります。

原理上、この問題は非常に簡単な方法で解決できます。LinuxのSLOB(Simple-List-Of-Blocks)アロケータを見ながら、ヒープ・メモリー割り当てを実行する「slob_page_alloc」関数にブレークポイントを挿入します(図21)。更に、このブレークポイントにバーチャル・プロトタイプのデバッグ・コールバック・プロシージャをフックします。

画像

図21:ヒープ・メモリー・アサーションのスクリプト

対称型マルチプロセッシング(SMP)とキャッシュ・コヒーレンシ

SMPオペレーティング・システム(OS)のブリングアップは大きな難関です。まったく新しいSoCアーキテクチャと、新たにポーティングしたOSをここで初めて統合します。LinuxなどのSMP OSでは、プラットフォーム・ハードウェアはOSによって抽象化され、アプリケーション・ソフトウェアから隠蔽されます。

このため、OSはプラットフォームの複数のCPU間でプロセスを効率よくスケジューリングする必要があります。これらのアーキテクチャでは、メモリー内のデータ・コヒーレンシが非常に大きな課題となります。CPU 0であるプロセスが実行を開始後、CPU 1が実行を引き継ぐという場合があります。ここで、CPU 0のローカル・キャッシュに格納したデータをCPU 1のローカル・キャッシュでも利用できるようにするのが、いわゆるスヌープ制御ハードウェア・ユニット(SCU)の役割です(図24)。Armが発表したbig.LITTLEプロセッシング・システムでは、2つのヘテロジニアスSMP CPUクラスタ(Cortex-A53とCortex-A57)のコヒーレンシを維持する必要があるため、キャッシュ・コヒーレンシの複雑さは特に顕著です。

画像

図24:対称型マルチプロセッシング(SMP)

カテゴリートップ