普段使用するデバッグツールの無い環境を考えてみる
マルチコアデバッグとは少し離れますが、デバッグ環境が十分ではない時のことを考えてみます。
普段使うデバッグツールはgdb等のデバッガやprintfと思います。これらの用途は。
これらの情報はデバッグで普通に使用すると思います。
なお、ここに上げている項目の中で、「コールスタック」は、現時点の関数がどのような親関数(階層的に)呼ばれているかを示す情報です。また、「提供されている情報」は、プログラム停止位置がソースのどこにあたるかを知る手立てとなるような情報です。
gdbやprintfの無い環境でこれらの情報が得られるでしょうか。
gdbやprintfの無い環境でも、メモリやレジスタの参照はできると思います。それができなければデバッグは不可能でしょう。おそらくメモリやレジスタの変更も可能だと思います。
レジスタとメモリの読み書きができれば、デバッグのための情報は得られそうです。方法は。
- ソースプログラムとの対応付け
ソースプログラムの関数や変数のアドレスを求めるには、プログラムビルド時のリンクアドレス情報(リンクマップ)と各ファイルのアセンブル情報(アセンブルリスト)が必要です。ファイルの先頭アドレスにファイル内のオフセットアドレスを加算する方法などにより求めます。コンパイラの生成するデバッグ情報も変数や関数、特定のソースプログラム行のアドレスを求める助けになります(デバッグ情報はアセンブルソースの中に書かれていることが良くあります)。
- プログラムの現在位置(アドレス)
プログラムが停止した時のアドレスは一般的にプログラムカウンタと呼ばれるレジスタに入っています。CPUにより別のレジスタ名のこともありますが、同様のレジスタがあります。このレジスタの値をリンクマップとアセンブルリスト情報を元に計算することでソースプログラムの位置を特定できます。
- コールスタック
コールスタックを調べることで関数の呼び出し状況が解りますが、コールスタックの構造はコンパイラにより異なるので、個々のコンパイラが作るスタック構造を知らなければなりません。
スタックメモリの現在位置はスタックポインタと呼ぶレジスタに保存されていますが、このレジスタもCPUやコンパイラにより異なります。簡単ではありませんが、情報を得ることができれば、スタックを辿って関数の呼び出し状況を確認することができます。スタックの一例を前回のブログに掲載しています。
以上の情報はビルドツールやコンパイラのマニュアルで確認できるでしょう。
Cソースファイル内変数の値を確認できれば、様々なことができるようになります。
- プログラム通過ポイントの確認
ソースプログラムの要所要所に通過情報変数にユニークな値を代入する改造を行えば、どこまで通過したのかが判りますし、配列にして情報を追加してゆけば通過順も判ります。
- ブレーク
マニアックな方法ですが、アセンブラ命令を書き換えることで可能になります。
止めたい 位置の命令を停止命令やループ命令に書き換えれば、プログラムが停止します。再開する時には元の命令に戻します(CPUによってはプログラムカウンタも戻す必要があるかもしれません)。
手間のかかる作業になりますが、メモリやレジスタの読み書きができれば、デバッグする方法は色々あります。
今回はディープな内容になりましたが、アセンブルリストやリンクマップをみると色々と勉強になりますので、機会があったら挑戦してみてください。
コメントをお書きください