Mona OSにおけるデバッグ技法 - 2.落ちる場所を特定


Mona でアプリケーションを開発していると

 access denied.address = 0x900C5000 Process HAPPY.EX5 killed  eip=0xA0043098name=HAPPY.EX5

のように突然アプリケーションが落ちる場合があります。
Mona には現時点でデバッガがありません。
ソースコード上のどこで落ちたかを知るには以下で紹介する方法を使います。

大まかな流れ

  1. MAP ファイルで場所の特定を試みる
  2. logprintf で場所の特定を試みる
  3. DLLの中を疑ってみる

MAP ファイルで場所の特定を試みる

アプリケーションが落ちたアドレスは

killed  eip=0xA0043098

のように eip= の後に続いたアドレスです。
このアドレスを覚えておいてください。(ちなみにこのアドレスは後述のシリアルコンソールのログにも出力されます)


落ちたアプリケーションのソースコードディレクトリに アプリケーション名.map というファイルがあるので開きます。
このファイルはリンク時の アドレス => 関数や変数などのシンボル というマッピング情報を出力したファイルです。
先ほどのアドレスと見比べることで落ちた場所が分かります。
完全にアドレスが一致しなくても、 20-30byteくらいであればその近辺で落ちたのだなということが分かります。


もし落ちたアドレスが、このマッピングファイルの中に含まれる範囲より大きい場合は「 DLL の中を疑ってみる」に進んでください。

logprintfで場所の特定を試みる

logprintf 関数を利用するとシリアルコンソールに文字列を書き込めます。
QEMU を -serial file:/tmp/qemu_mona.log のように -serial オプションで起動していると logprintf の出力は /tmp/qemu_mona.log に吐かれます。
これを利用することで簡単にトレースログをとることができます。
例えばソースコード中に

 logprintf("%s %s:%d\n", __func__, __FILE__, __LINE__);

とたくさんバラまいておけば、処理がどこまで進んだか簡単に知ることができます。

DLLの中を疑ってみる

アドレスが 0xAxxxxxxx でかつ map ファイルにアドレスが見つからない場合は DLL の中で落ちている可能性が高いです。
DLL の特定は以下の手順で行います。

  1. 実行時に落ちるアドレス周辺のコードをlogprintf でダンプする
  2. ダンプした16進バイト列を DLL で grep して DLL を特定
    • for i in `find -name "*.DLL"` ; do echo $i; od -tx4 $i | grep -A1 -B1 'f3fc104d'; done
  3. 特定された DLL を PE Explorer などで逆アセンブルしてアドレスとシンボルを一致させて落ちている箇所を調べる
  4. grep 'F3' -A2 -B2 ~/disassemble.txt | grep 'FC' -A2 -B2 |grep '10' -A2 -B2 |grep '4D' -A2 -B2

その他

上記を試してもだめならひげぽんに苦情を言いましょう。