クラッシュ ダンプ分析

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

ミニダンプの記述

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

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

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

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

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

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

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

  • プロジェクトにコードを追加します。 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++ をクリックします。 既定では、[ 全般 ] 設定が表示されます。 プロジェクトのプロパティ ページの右側で、 デバッグ情報の形式Program Database (/Zi) に設定します。
  2. プロパティ ページの左側で、[ リンカー] を展開し、[ デバッグ] をクリックします。 プロパティ ページの右側で、[ デバッグ情報の生成 ] を [はい ] (/DEBUG) に設定します。
  3. [ 最適化] をクリックし、 参照先を エリミネート未参照データ (/OPT:REF) に設定します。
  4. [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 Central のデバッグ ツールから入手できるデバッグ ツールWindowsダウンロードしてインストールすることで、最新バージョンのDumpchk.exe Windows入手することもできます。

ミニダンプの分析

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

まとめ

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