クラッシュ ダンプ分析

リリース前にすべてのバグが見つかるわけではありません。つまり、例外をスローするすべてのバグがリリース前に見つかるわけではありません。 幸いなことに、Microsoft はプラットフォーム SDK に、開発者がユーザーによって検出された例外に関する情報を収集するのに役立つ関数を含んでいます。 MiniDumpWriteDump 関数は、プロセス領域全体を保存せずに、必要なクラッシュ ダンプ情報をファイルに書き込みます。 このクラッシュ ダンプ情報ファイルはミニダンプと呼ばれます。 この技術記事では、ミニダンプを記述して使用する方法に関する情報を提供します。

ミニダンプの作成

ミニダンプを記述するための基本的なオプションは次のとおりです。

  • 何もしない。 プログラムがハンドルされない例外をスローするたびに、Windows によってミニダンプが自動的に生成されます。 Windows XP 以降、ミニダンプの自動生成を利用できます。 ユーザーが許可した場合、ミニダンプは、Windows エラー報告 (WER) を介して開発者ではなく Microsoft に送信されます。 開発者は、 Windows デスクトップ アプリケーション プログラムを使用して、これらのミニダンプにアクセスできます。

    WER を使用するには、次のものが必要です。

    • Authenticode を使用してアプリケーションに署名する開発者
    • アプリケーションには、すべての実行可能ファイルと DLL に有効な VERSIONINFO リソースがあります

    ハンドルされない例外のカスタム ルーチンを実装する場合は、例外ハンドラーで ReportFault 関数を使用して、自動ミニダンプを WER に送信することを強くお勧めします。 ReportFault 関数は、 への接続と WER へのミニダンプの送信に関するすべての問題を処理します。 WER にミニダンプを送信しない場合は、Windows 用ゲームの要件に違反します。

    WER のしくみの詳細については、「Windows エラー報告のしくみ」を参照してください。 登録の詳細については、MSDN の ISV ゾーンWindows エラー報告の概要に関するページを参照してください。

  • Microsoft Visual Studio Team System の製品を使用します。 [ デバッグ ] メニューの [ 名前を付けてダンプを保存 ] をクリックして、ダンプのコピーを保存します。 ローカルに保存されたダンプの使用は、社内テストとデバッグのオプションにすぎません。

  • プロジェクトにコードを追加します。 MiniDumpWriteDump 関数と適切な例外処理コードを追加して、ミニダンプを保存して開発者に直接送信します。 この記事では、このオプションを実装する方法について説明します。 ただし、 MiniDumpWriteDump は現在マネージド コードでは機能せず、Windows XP、Windows Vista、Windows 7 でのみ使用できます。

スレッド セーフ

MiniDumpWriteDump は、DBGHELP ライブラリの一部です。 このライブラリはスレッド セーフではないため、 MiniDumpWriteDump を使用するすべてのプログラムは、 MiniDumpWriteDump を呼び出す前にすべてのスレッドを同期する必要があります。

コードを使用したミニダンプの記述

実際の実装は簡単です。 MiniDumpWriteDump の使用方法の簡単な例を次に示します。

#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>

int GenerateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH]; 
    WCHAR szFileName[MAX_PATH]; 
    WCHAR* szAppName = L"AppName";
    WCHAR* szVersion = L"v1.0";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPath( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectory( szFileName, NULL );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", 
               szPath, szAppName, szVersion, 
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, 
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, 
               GetCurrentProcessId(), GetCurrentThreadId());
    hDumpFile = CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, 
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), 
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);

    return EXCEPTION_EXECUTE_HANDLER;
}


void SomeFunction()
{
    __try
    {
        int *pBadPtr = NULL;
        *pBadPtr = 0;
    }
    __except(GenerateDump(GetExceptionInformation()))
    {
    }
}

この例では、 MiniDumpWriteDump の基本的な使用方法と、それを呼び出すために必要な最小限の情報を示します。 ダンプ ファイルの名前は開発者が指定します。ただし、ファイル名の競合を回避するには、アプリケーションの名前とバージョン番号、プロセス ID とスレッド ID、および日付と時刻からファイル名を生成することをお勧めします。 これは、ミニダンプをアプリケーションとバージョン別にグループ化し続けるのにも役立ちます。 ミニダンプ ファイル名を区別するために使用される情報の量は、開発者が決定する必要があります。

前の例のパス名は 、GetTempPath 関数を呼び出して一時ファイル用に指定されたディレクトリのパスを取得することによって生成されたことに注意してください。 このディレクトリの使用は、最小限の特権を持つユーザー アカウントでも機能し、ミニダンプが不要になった後にハード ドライブ領域を占有することもできなくなります。

毎日のビルド プロセス中に製品をアーカイブする場合は、必要に応じて古いバージョンの製品をデバッグできるように、ビルドのシンボルも含めるようにしてください。 また、シンボルの生成中に完全なコンパイラ最適化を維持するための手順を実行する必要もあります。 これを行うには、開発環境でプロジェクトのプロパティを開き、リリース構成に対して次の操作を行います。

  1. プロジェクトのプロパティ ページの左側にある [C/C++] をクリックします。 既定では、[ 全般 ] 設定が表示されます。 プロジェクトのプロパティ ページの右側で、[ デバッグ情報の形式 ] を [プログラム データベース (/Zi)] に設定します。
  2. プロパティ ページの左側にある [ リンカー] を展開し、[ デバッグ] をクリックします。 プロパティ ページの右側で、[ デバッグ情報の生成 ] を [ はい (/DEBUG)] に設定します。
  3. [ 最適化] をクリックし、[ 参照 ] を [Eliminate Unreferenced Data (/OPT:REF)] に設定します。
  4. [ ENABLE COMDAT Folding]\(COMDAT フォールディングを有効にする \) を設定して 、冗長 COMDAT (/OPT:ICF) を削除します。

MSDN には、 MINIDUMP_EXCEPTION_INFORMATION 構造と MiniDumpWriteDump 関数に関する詳細情報が含まれています。

Dumpchk.exeの使用

Dumpchk.exeは、ダンプ ファイルが正しく作成されたことを確認するために使用できるコマンド ライン ユーティリティです。 Dumpchk.exeでエラーが発生した場合、ダンプ ファイルは破損しており、分析できません。 Dumpchk.exeの使用方法の詳細については、「Dumpchk.exe を使用してメモリ ダンプ ファイルを確認する方法」を参照してください。

Dumpchk.exeは Windows XP 製品 CD に含まれており、Windows XP 製品 CD の Support\Tools\ フォルダーで Setup.exeを実行することで、System Drive\Program Files\Support Tools\ にインストールできます。 Windows Hardware Developer CentralWindows デバッグ ツールから入手できるデバッグ ツールをダウンロードしてインストールすることで、最新バージョンのDumpchk.exeを入手することもできます。

ミニダンプの分析

分析のためにミニダンプを開くのは、ミニダンプを作成するのと同じくらい簡単です。

ミニダンプを分析するには

  1. Visual Studio を開きます。
  2. [ ファイル ] メニューの [ プロジェクトを開く] をクリックします。
  3. [ファイルの種類][ダンプ ファイル] に設定し、ダンプ ファイルに移動して選択し、[開く] をクリックします。
  4. デバッガーを実行します。

デバッガーは、シミュレートされたプロセスを作成します。 シミュレートされたプロセスは、クラッシュの原因となった命令で停止します。

Microsoft パブリック シンボル サーバーの使用

ドライバー レベルまたはシステム レベルのクラッシュのスタックを取得するには、Microsoft パブリック シンボル サーバーを指す Visual Studio を構成することが必要な場合があります。

Microsoft シンボル サーバーへのパスを設定するには

  1. [ デバッグ ] メニューの [ オプション] をクリックします。
  2. [ オプション ] ダイアログ ボックスで、[デバッグ] ノード 開き、[ シンボル] をクリックします。
  3. デバッグ時 にシンボルを手動で読み込む場合を除き、シンボルが手動で読み込まれた場合にのみ上記の場所を検索 する] が選択されていないことを確認します。
  4. リモート シンボル サーバーでシンボルを使用している場合は、シンボルをコピーできるローカル ディレクトリを指定することで、パフォーマンスを向上させることができます。 これを行うには、 シンボル サーバーからこのディレクトリへのキャッシュ シンボルのパスを入力します。 Microsoft パブリック シンボル サーバーに接続するには、この設定を有効にする必要があります。 リモート コンピューターでプログラムをデバッグする場合、キャッシュ ディレクトリはリモート コンピューター上のディレクトリを参照することに注意してください。
  5. [OK] をクリックします。
  6. Microsoft パブリック シンボル サーバーを使用しているため、[エンド ユーザー ライセンス契約] ダイアログ ボックスが表示されます。 [ はい ] をクリックして契約に同意し、シンボルをローカル キャッシュにダウンロードします。

WinDbg を使用したミニダンプのデバッグ

Windows デバッグ ツールの一部であるデバッガーである WinDbg を使用して、ミニダンプをデバッグすることもできます。 WinDbg を使用すると、Visual Studio を使用せずにデバッグできます。 Windows デバッグ ツールをダウンロードするには、「Windows Hardware Developer CentralWindows デバッグ ツール」を参照してください。

Windows デバッグ ツールをインストールした後、WinDbg にシンボル パスを入力する必要があります。

WinDbg でシンボル パスを入力するには

  1. [ ファイル ] メニューの [ シンボル パス] をクリックします。

  2. [ シンボル検索パス ] ウィンドウで、次のように入力します。

    "srv\*c:\\cache\*https://msdl.microsoft.com/download/symbols;"

ミニダンプでのCopy-Protection ツールの使用

また、開発者は、コピー保護スキームがミニダンプにどのように影響するかを認識する必要があります。 ほとんどのコピー保護スキームには独自の descramble ツールがあり、 MiniDumpWriteDump でこれらのツールを使用する方法を学習するのは開発者の責任です。

まとめ

MiniDumpWriteDump 関数は、製品のリリース後にバグを収集して解決するのに非常に便利なツールです。 MiniDumpWriteDump を使用するカスタム例外ハンドラーを記述すると、開発者は情報コレクションをカスタマイズし、デバッグ プロセスを改善できます。 関数は、C++ ベースのプロジェクトで使用できる十分な柔軟性があり、プロジェクトの安定性プロセスの一部と見なす必要があります。