Windows Error Reporting Part.3

Part.1 と Part.2 で WER の仕組みと前提となる SEH の概要をお伝えしました。Part.3 では、いよいよ WER の
API を紹介したいと思います。

Windows Error Reporting Part.1 で WER は Microsoft WER サイトに採取したデータを送信し、
その動きをレジストリで制御することができると紹介しましたが、API を使うと、一時的に現在のプロセスの設定のみを
変更することができます。

一つだけ注意があります。WerGetFlags() は、WerSetFlags() の結果を取得するときに使う用途になっているので
WerSetFlags() を呼び出さずに、いきなり WerGetFlags() を呼びだすと、エラーになります。

次に、WER の問題レポートの作成ですが、MSDN にある

に従い、以下の流れで処理します。

  1. WER_REPORT_INFORMATION 構造体を準備する
  2. WerReportCreate() を呼び出し、WER 問題レポートを作成する
  3. WerReportSetParameter() を呼び出して、パラメーターを追加する
  4. WerReportAddFile() を呼び出して、レポートに独自のファイルを追加する
  5. WerReportAddDump() を呼び出して、ミニダンプをレポートに追加する
  6. WerReportSubmit() を呼び出して、レポートを送信するか、ローカルキューに保存する
  7. WerReportCloseHandle() でリソースを解放して終了する

イメージがわかるように、実際の画面との対応を行ってみます。
まず、WER 問題レポートの表示です。

この投稿の続きを読む

Windows Error Reporting Part.2

Part.1 では、WER の概要をお伝えしました。Part.2 では、実際に WER の API を紹介したいところですが
WER の前提として、知っておかなければならない知識があります。例外処理についてです。

C++ では、構造化例外処理(SEH: Structured Exception Handling)と C++ 例外処理の 2 種類を使うことが
できます。SEH は OS が提供しているもので、C++ 例外処理は名前の通り、C++ 言語が提供しています
WER を使いこなすためには、SEH を理解しておく必要があります。
C++ の例外処理は別の機会でネタにして、今回は SEH の最低限の知識を復習します。

SEH は、__try/__except や __try/__finally を使い実装しますが、代表的な使い方はこんな感じです。

void MyFunc (void)
{
    __try
    {
        __try
        {
            // 処理
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            // 例外ハンドラ
            // __try ブロック内で何かしらの例外処理が発生したときに 実行される
        }
    }
    __finally
    {
        // 終了ハンドラ
        // 例外が有ろうと無かろうと常に実行される。後処理で使うことが多い
    }
}

__except では、例外フィルターを指定するのですが、使うことができるのは

  • EXCEPTION_EXECUTE_HANDLER
    対応する __try ブロック内で例外処理が発生すれば、必ず実行される
  • EXCEPTION_CONTINUE_SEARCH
    呼び出しチェイン内の上位にある次の __except ブロックを実行させる
  • EXCEPTION_CONTINUE_EXECUTION
    対応する __try ブロック内で発生した例外を無視する

の 3 つです。図に書くと、次のような動きになります。

この投稿の続きを読む

Windows Error Reporting Part.1

ちょっと深いデバッグネタを紹介していきたいと思います。
Vista 以降、OS がアプリケーションに対して提供するデバッグアーキテクチャは大きく変更されました。

XP/2003 までは、ワトソン博士というのがあったのですが、Vista 以降は、大体、こんな仕組みで動いています。
カーネルが介入することによって、エラーロジック(ワトソン博士)そのもののエラーがなくなったので、
ほぼ間違いなく、エラー処理が実行されるというわけです。

デバッグアーキテクチャ

  1. WER サービス(WerSvc)は、OS ブート時にカーネルに対して、ポートを登録する。
  2. アプリケーションエラーは、一番最初に、カーネルが検知する。そして、カーネルがアプリケーションに
    対して、エラーが発生したことを通知するわけです。(これが、First Chance)
  3. アプリケーションの例外ハンドラーや、未処理の例外はカーネルに対して EXCEPTION_CONTINUE_SEARCH を
    返す。
  4. カーネルは、ポートを通して、WerSvc を呼び出す。
  5. WerSvc は、Windows Problem Reporting(Windows 問題レポート: werfault.exe)を呼び出し、画面表示する。
  6. もし、JIT デバッガが有効になっていたら、エラーを起こしたアプリケーションにデバッガをアタッチさせる。
  7. Windows Problem Reporting は、JIT デバッガを起動したことをカーネルに返し、カーネルはデバッガに例外を
    ディスパッチする。

WER_サービス

アプリケーションがエラーになった際に表示される以下の画面ですが、これが werfault.exe です。

この投稿の続きを読む

Windows Installer のカスタムアクションをデバッグする

結構、便利なので紹介します。元ネタは

です。
今回は、MSI でカスタムアクションを実装することができる人向けということを前提としています。
ちょっとディープな内容になってしまうかもしれません。

MSI を作っているときに、標準アクションではどうしてもできない処理があり、カスタムアクションを用意することが
あります。もちろん、カスタムアクションを作る際にきちんとデバッグしておくわけですが、そのデバッグを通り抜けて
しまったバグをどうやってデバッグ/調査しようかと悩むことがあるかもしれません。
Windows Installer は、非常によくできていて、カスタムアクションのデバッグを支援する仕組みを持っています。
その方法ですが、次のような流れになります。

  1. システム環境変数に MsiBreak 変数を用意して、カスタムアクション名を値に設定する。
  2. 管理者権限でコマンドプロンプトを開き、msiexec コマンドでインストーラーを実行する。
  3. WinDBG でカスタムアクション用の msiexec.exe にプロセスアタッチしてカスタムアクションをデバッグする。

MsiBreak システム変数で設定してカスタムアクションが実行されるときに、Windows Installer が一度、Break してくれると
いう仕組みを持っているわけです。
以前、カスタムアクションは、カスタムアクション用の msiexec.exe が起動されて、その中で実行されると紹介しましたが
その msiexec.exe にデバッガでアタッチしてデバッグしようというわけです。

この投稿の続きを読む

シンボルサーバーの構築方法

ちょっと、ディープなネタです。

WinDbg でダンプファイル解析を行う際、OS のシンボル情報が必要になります。
ダンプファイルを開いた際、シンボル情報が読み込めないと、

のように、”シンボル情報がないよ” と表示されてしまいます。
このまま進めていっても、ntdll.dll のシンボル情報がないので解析するのが非常に困難です。
きちんとシンボル情報を読み込ませると

となります。

シンボル情報を含んでいるシンボルサーバーは、Microsoft がインターネット上で公開していますので
通常は、それを使えば何も問題はありません。

WinDbg でこれを指定する場合には、File – Symbol File Path メニューで

を指定します。
ただ、インターネットに接続していない環境でもダンプ解析を行いたいという場合があるかもしれません。
そのような時には、シンボルサーバーを手元に構築しておくとよいかもしれません。

シンボルサーバーの構築方法について紹介します。(やっと本題)

  1. ネットワーク共有を作成する
    \\<server>\Symsrv
  2. Microsoft のサイトより、シンボルファイルをダウンロードする
    http://www.microsoft.com/japan/whdc/devtools/debugging/symbolpkg.mspx
  3. ネットワーク共有にシンボルを追加する
    ”Debugging Tools for Windows” にある Symstore コマンドを使う

このような方法でシンボルサーバーを構築することができます。
1 は今更説明するまでもないので割愛します。
2 ですが、例えば、Windows Server 2003 SP2 上で動いているアプリケーションのダンプファイルを解析したいと
いう場合には、

  • Windows Server 2003 SP2 のシンボル
  • Windows Server 2003 SP1 のシンボル
  • Windows Server 2003 のシンボル

の 3 つを用意しておく必要があります。OS が SP2 だから、シンボルも SP2 だけというわけではありませんので
注意してください。
3 の Symstore コマンドの代表的な使い方を紹介します。
(詳しくは、Debugging Tools for Windows のヘルプを参照してください)

例)

  • シンボルをダウンロードして展開したフォルダー : E:\download\symbols\2003\SP2
  • シンボルサーバーを構築するフォルダー : F:\Symsrv\Win2003\x86

上記にシンボルサーバーを構築する際の Symstore コマンドは以下のように使います。

symstore add /r /f E:\download\symbols\2003\SP2\*.* /s F:\Symsrv\Win2003\x86 /t “Windows Server 2003” /v “SP2”

  • /r: SP2 フォルダーにあるサブフォルダーも参照する
  • /f: 展開済みシンボルがあるフォルダー
  • /s: シンボルサーバーを構築するフォルダー
  • /t、/v: 製品名、バージョン(任意でよい)

このコマンドで、F:\Symsrv\Win2003\x86\SP2 というフォルダーが作成され、シンボル情報が構築できます。

あとは、WinDbg でこれを指定すればよいだけです。

参考情報

なお、WinDbg は常に最新のものを使うようにしましょう。

Virtual PC を使って、Live Debug する

Virtual PC を使った 仮想 OS のLive Debug を紹介しちゃいます。
今までは、2 台の PC をシリアルケーブル(COMポート)で接続して、Live Debug をやっていたのですが
Virtual PC を使うと、一台で出来る(名前付きパイプを仮想シリアルケーブルに見立てる)ので、かなり重宝します。

【今回の環境】

ホスト OS : Windows 7
ターゲット OS: Windows XP(Windows 7 の XP Mode)

あと、デバッグには、WinDbg を使いますので、予め、ダウンロードしてホスト OS 側にインストールして
おいてください。

まず、XP Mode の設定画面で、COM1 を変更します。名前付きパイプの設定を「\\.\pipe\debug」とします。

次に、XP Mode を起動して、Windows XP(ターゲット OS)の設定を行います。boot.ini ファイルを編集します。
既存のブートレコードをコピーして、デバッグ用の起動オプションを追加します。

/debug /debugport=com1 /baud=115200

を追加します。そして、システムの起動と回復で、起動時プロファイルを変更しておきます。

ここまで終わったら、Windows XP(ターゲット OS)を再起動します。

続いて、ホスト OS 側で、WinDbg を起動します。

“File メニュー” – “Kernel Debugging” を選択して、設定画面を開きます。

ここで、”Pipe“ にチェックを入れ、Port の部分に XP Mode の COM1 設定で入力した名前付きパイプを入れます。
で、OK をクリックして、しばらく待つと…

という具合に接続できました!
WinDbg で OS のシンボルを設定するのも忘れないようにしてください。

シンボルをダウンロードするのが面倒だったら、

http://msdl.microsoft.com/download/symbols

を指定すると、ネットワーク経由で、シンボルをダウンロードして使ってくれます。
この辺は、WinDbg のヘルプを参照してください。ここでは詳しい説明は割愛します。

これで、WinDbg からターゲット OS である Windows XP の Live Debug ができるようになりました。
もっとも、Live Debug するようなことにならないのが、一番よいのですが…。

デバッグツール あれこれ (その 1)

開発支援をしているとよく使うデバッグツールがあります。
自分でもどこかにまとめておきたいなということで。

  • デバッグ ツールとシンボル
    http://www.microsoft.com/japan/whdc/devtools/debugging/debugstart.mspx
    自分の意思に関わらず、ダンプが送られてきますから…WinDbg が無いとダンプ見られないし。
    32bit 版と 64bit 版があります。
    シンボルパッケージは Web 参照(Microsoft Symbol Server)してもいいですが、私は自分用のシンボルサーバーを構築しています。
  • Fiddler (Web Debugging Proxy)
    http://www.fiddlertool.com/fiddler/
    ブラウザと Web サーバーの間にプロキシを噛ませて HTTP 通信をモニタリングしようというものです。
  • Microsoft Network Monitor 3.2
    http://www.microsoft.com/downloads/details.aspx?FamilyID=f4db40af-1e08-4a21-a26b-ec2f4dc4190d&DisplayLang=en
    Microsoft 版の LAN アナライザです。非常に使いやすい UI です。
    今、3.3 がベータ中です。
    ただ、SSL を解析しようとすると不便です。せめて、SSL の 3WAY ハンドシェイクくらいはキャプチャしてほしいです。
  • Wireshark (鮫ちゃん)
    http://www.wireshark.org/
    ネットワークパケットをキャプチャするなら、やはり、これが最強かな。
    以前の Ethereal からモデルチェンジしました。

Vista で カーネルデバッグをやりたい

Vista では、boot.ini がなくなってしまたっため、従来の方法ではカーネルデバッグの設定ができません。
では、どうするのかというと…自分で書こうと思ったら、Microsoft のページに見つけました。

WHDC: Windows Vista のデバッグ

ここを参考にしてください。
関連する URL も記述しておきましょう。

これで終わってしまうと物足りないので、おさらいの意味も込めて、レジスタについての説明も記載しておきます。

汎用レジスタ

EAX: アキュムレータ
    演算処理の中心となるレジスタ。関数のリターン値はここです。
EBX: ベースレジスタ
    メモリをアクセスする場合のベースアドレスです。
ECX: カウンタ
    プログラム上のループの回数をカウントします。
EDX: データレジスタ
    アキュムレータの補助的なレジスタとして乗除算で使用されます。

インデックスレジスタ

ESI: ソースインデックス
    ストリング命令のアドレスを格納します。
EDI: ディスティネーションインデックス
    ストリング命令のディスティネーションアドレスを格納します。

ポインタレジスタ

ESP: スタックポインタ
    データやアドレスをスタック領域に PUSH したり POP したりするのに使用されます。
EBP: ベースポインタ
    スタック領域上のベースとなるアドレスを記憶します。
EIP: インストラクションポインタ
    実行するアセンブラ命令を示すために利用されます。

機会があれば、デバッグ入門なんてものもやろうかしら。