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 <Dbghelp.h>
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开始调试
-
本机编译出来的,可自动根据堆栈信息定位源代码Crash的位置
-
非本机编译/版本不匹配,则可根据堆栈信息调试
-
如果需要关闭【源文件与PDB文件不匹配】的提示,在Tools->Options->Debugging->General里设置
Release工程下如何生成PDB
VS工程设置Release下生成PDB
- 项目->属性->C/C++->General->Debug Information Format->Program Database
- 项目->属性->C/C++->Optimization->Optimization->Disabled(/Od),这一步貌似也可不设置
- 项目->属性->Linker->Debugging->Generate Debug Info->Yes(/DEBUG)
CMake设置VS工程的Release下生成PDB
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
对应于
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")
对应于
关于工程设置选项的解释
- 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