LoginSignup
22
15

More than 5 years have passed since last update.

クラッシュ時にダンプファイルを出力する

Last updated at Posted at 2018-04-07

プログラムがクラッシュした際、ダンプファイルを出力するようにしておくと便利なことがあります。
例えば、ユーザー環境でクラッシュした際にダンプファイルを取得できれば、どこに問題があったのか解決しやすくなります。

Windows の構造化例外処理を用い、クラッシュ時にダンプファイルを出力してみます。

ほぼ、これそのままです。
クラッシュ ダンプの分析

クラッシュ時にダンプファイルを出力する

クラッシュ時に処理を行うには、Windows の構造化例外処理を用います。
https://msdn.microsoft.com/ja-jp/library/swezty51.aspx
メイン関数の中身を __try__except で囲みます。

ダンプファイルの作成には MiniDumpWriteDump を使用します。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms680360(v=vs.85).aspx

こんな感じです。

main.cpp
#include <Windows.h>
#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>
#include <strsafe.h>
#include <tchar.h>

#include <iostream>

int GenerateDump(EXCEPTION_POINTERS* expPtr) {
    TCHAR desktopDir[MAX_PATH];
    SHGetSpecialFolderPath(NULL, desktopDir, CSIDL_DESKTOPDIRECTORY, FALSE);

    SYSTEMTIME localTime;
    GetLocalTime(&localTime);

    TCHAR* appName = _T("dump_test");

    TCHAR dumpPath[MAX_PATH];
    StringCchPrintf(
        dumpPath, MAX_PATH, _T("%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp"),
        desktopDir, appName, localTime.wYear, localTime.wMonth, localTime.wDay,
        localTime.wHour, localTime.wMinute, localTime.wSecond,
        GetCurrentProcessId(), GetCurrentThreadId());

    HANDLE dumpFile =
        CreateFile(dumpPath, GENERIC_READ | GENERIC_WRITE,
                   FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    MINIDUMP_EXCEPTION_INFORMATION expInfo;
    expInfo.ThreadId = GetCurrentThreadId();
    expInfo.ExceptionPointers = expPtr;
    expInfo.ClientPointers = TRUE;

    BOOL miniDumpSuccessful =
        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile,
                          MiniDumpWithDataSegs, &expInfo, NULL, NULL);

    return EXCEPTION_EXECUTE_HANDLER;
}

int main() {
    __try {
        int* badPtr = NULL;
        *badPtr = 0;
    } __except (GenerateDump(GetExceptionInformation())) {
    }

    return 0;
}

badPtr をアクセスした際にクラッシュします。

ダンプファイルはデスクトップに dump_test-<日付>-<時間>-<プロセスID>-<スレッドID>.dmp の形式で出力されます。

PDBファイルについて

ビルド時に出力されるPDBファイルはダンプファイルを解析する際に必要になります。
実行ファイルとPDBファイルをともに保存しておきます。

CMake で生成されるプロジェクトについて

CMake で生成されるプロジェクトの構成には以下のものがあります。

  • Debug
  • MinSizeRel
  • Release
  • RelWithDebInfo

このうち、「MinSizeRel」と「Release」についてはPDBファイルが生成されないので、注意が必要です。

クラッシュダンプを解析する

ユーザー環境などから出力されたダンプファイルを取得出来たら、Visual Studio で解析します。
この時、配布時と同じソースコードが必要になるので、ソースコード管理ツール等でタグ付けしておきましょう。
また、実行ファイル、PDBファイル、ダンプファイルを同一ディレクトリに配置しておくと、デバッグの際 PDB の検索が簡単になります。

.dmp ファイルをダブルクリックすると、次のような画面が表示されます。

debug_01.png

ネイティブのみでデバッグ をクリックします。

debug_02.png

デバッガがクラッシュした箇所で停止していることが確認できます。

ソースコードのパスが違う場合

ビルド環境と開発環境で、ビルドパスが違う場合があります。
その際、ソースファイルの検索画面が表示されるので、ソースのあるディレクトリを指定します。

debug_03.png

ソースコードが変更されている場合

ソースコードが変更されている場合は、次の画面が表示されます。

debug_04.png

「いいえ」を選択すると、ソースファイルの検索画面が表示されるので、同じバージョンのソースを指定します。

参照

22
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
15