C++-Dump文件的创建和调试

  • Dump文件的创建方法
  • Dump文件的调试
  • Release工程下如何生成PDB

Dump文件的创建方法

Windows创建Dump文件的API-MiniDumpWriteDump

BOOL
WINAPI
MiniDumpWriteDump(
    _In_ HANDLE hProcess,
    _In_ DWORD ProcessId,
    _In_ HANDLE hFile,
    _In_ MINIDUMP_TYPE DumpType,
    _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
    _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
    _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam
    );
  • 该API在系统的DbgHelp里,需要动态加载DbgHelp.dll或静态链接DbgHelp.lib
  • 同时#include

Windows保存Dump信息结构体-MINIDUMP_EXCEPTION_INFORMATION

typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
    DWORD ThreadId; 
    PEXCEPTION_POINTERS ExceptionPointers;
    BOOL ClientPointers;
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;

编写创建生成Dump文件的函数

bool CreateDumpFile(std::string filePath , PEXCEPTION_POINTERS pExcept)
{
    MINIDUMP_EXCEPTION_INFORMATION exceptInfo;
    exceptInfo.ExceptionPointers = pExcept;
    exceptInfo.ThreadId = GetCurrentThreadId();
    exceptInfo.ClientPointers = TRUE;

    HANDLE dumpFile = ::CreateFile((LPCSTR)filePath.c_str(), GENERIC_WRITE, 0, NULL,
                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (dumpFile != INVALID_HANDLE_VALUE)
    {
        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, MiniDumpNormal, &exceptInfo, NULL, NULL);
        CloseHandle(dumpFile);
        return true;
    }
    return false;
}

创建生成Dump 文件的文件名函数

std::string GetDumpFileName()
{
    std::stringstream fn;
    std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    fn << GetTempFolder() << "SysCrash_" << std::put_time(std::localtime(&tt), "%Y-%m-%d-%H.%M.%S") << ".dmp";
    return fn.str().c_str();
}

创建需要交给windows(程序崩溃时)的回调函数

LONG WINAPI SysExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo)
{
    if (IsDebuggerPresent())
    {
        return EXCEPTION_CONTINUE_SEARCH;
    }

    std::string filename = GetDumpFileName();
    dhlLog.LOG_ERR("System Crashed!");
    if (CreateDumpFile(filename, lpExceptionInfo))
    {
        dhlLog.LOG_INFO("Dump File: %s", filename.c_str());
    }
    
    return EXCEPTION_EXECUTE_HANDLER; //stop in the crash point
    //return EXCEPTION_CONTINUE_EXECUTION; //continue runing to next step
    //return EXCEPTION_CONTINUE_SEARCH; //continuous running the crash point
}
  • EXCEPTION_EXECUTE_HANDLER equ 1:异常可识别,程序可以结束了
  • EXCEPTION_CONTINUE_SEARCH equ 0:异常无法识别。 继续向上搜索堆栈查找处理程序,首先是所在的 try-except 语句,然后是具有下一个最高优先级的处理程序。于是windows调用默认的处理程序显示一个错误框,并结束 程序
  • EXCEPTION_CONTINUE_EXECUTION equ -1:表示错误已经被修复,请从异常发生处继续执行

在应用程序中设置异常发生时调用的函数

SetUnhandledExceptionFilter(SysExceptionFilter); //start
  • SetUnhandledExceptionFilter(SysExceptionFilter)确定出现没有控制的异常发生时调用的函数为SysExceptionFilter.
  • SysExceptionFilter为我们定义的回调函数,Windows会将崩溃信息通过参数传入这个回调函数,这时候可以创建Dump文件了。
SetUnhandledExceptionFilter(NULL); //end opt
  • 取消自定义处理except的函数

Dump文件的调试

保留pdb文件

  • 发布二进制文件生成的pdb文件需要保留,二进制文件和pdb文件版本一致比较好调试
    • dump,二进制文件,pdb的配置可以放在同一个目录
    • 也可打开dump文件工程,Set symbol paths里设置二进制文件和pdb文件所在的位置

调试

  • 点击Debug with Native Only开始调试
C++-Dump文件的创建和调试_第1张图片
  • 本机编译出来的,可自动根据堆栈信息定位源代码Crash的位置

  • 非本机编译/版本不匹配,则可根据堆栈信息调试

  • 如果需要关闭【源文件与PDB文件不匹配】的提示,在Tools->Options->Debugging->General里设置

C++-Dump文件的创建和调试_第2张图片

Release工程下如何生成PDB

VS工程设置Release下生成PDB

  • 项目->属性->C/C++->General->Debug Information Format->Program Database
C++-Dump文件的创建和调试_第3张图片
  • 项目->属性->C/C++->Optimization->Optimization->Disabled(/Od),这一步貌似也可不设置
C++-Dump文件的创建和调试_第4张图片
  • 项目->属性->Linker->Debugging->Generate Debug Info->Yes(/DEBUG)
C++-Dump文件的创建和调试_第5张图片

CMake设置VS工程的Release下生成PDB

set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")

对应于

C++-Dump文件的创建和调试_第6张图片

set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")

set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")

对应于

C++-Dump文件的创建和调试_第7张图片

C++-Dump文件的创建和调试_第8张图片

关于工程设置选项的解释

  • The **/Zi **option produces a separate PDB file that contains all the symbolic debugging information for use with the debugger. The debugging information is not included in the object files or executable, which makes them much smaller.

Use of /Zi does not affect optimizations. However, /Zi does imply /debug;
https://docs.microsoft.com/en-us/cpp/build/reference/z7-zi-zi-debug-information-format?view=vs-2015


  • The** /DEBUG** option creates debugging information for the executable.The linker puts the debugging information into a program database (PDB) file. It updates the PDB during subsequent builds of the program.An executable (.exe file or DLL) created for debugging contains the name and path of the corresponding PDB. The debugger reads the embedded name and uses the PDB when you debug the program. The linker uses the base name of the program and the extension .pdb to name the program database, and embeds the path where it was created. To override this default, set /PDB and specify a different file name.

https://docs.microsoft.com/en-us/cpp/build/reference/debug-generate-debug-info?view=vs-2015


  • /OPT:REF eliminates functions and data that are never referenced; When /OPT:REF is enabled, LINK removes unreferenced packaged functions and data, known as COMDATs. This optimization is known as transitive COMDAT elimination. The /OPT:REF option also disables incremental linking.

  • Use **ICF[=*****iterations*****] **to perform identical COMDAT folding. Redundant COMDATs can be removed from the linker output. The optional iterations parameter specifies the number of times to traverse the symbols for duplicates. The default number of iterations is 1. Additional iterations may locate more duplicates that are uncovered through folding in the previous iteration.

https://docs.microsoft.com/en-us/cpp/build/reference/opt-optimizations?view=vs-2015

参考了以下大神的文章

https://blog.csdn.net/bingqingsuimeng/article/details/73497198

你可能感兴趣的:(C++-Dump文件的创建和调试)