随着计算机应用的不断发展,软件崩溃问题难免会发生,而软件崩溃后留下的信息也是非常有价值的,这便是crashdumps。
一、什么是crashdumps
crashdumps是软件崩溃时产生的一种数据文件,记录了软件崩溃时的状态信息和执行堆栈信息。通过分析crashdumps能够找出崩溃原因,加速故障排查。
crashdumps是一种操作系统级别的特性,在Windows系统中,它通常使用“.dmp”后缀命名。crashdumps文件名包括了产生该文件的进程ID、线程ID和时间戳等信息。
// C++代码示例
// 生成Crash Dumps文件
BOOL GenerateDump(DWORD dwProcessId, DWORD dwThreadId, HANDLE hDumpFile)
{
BOOL bSuccess = FALSE;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE, dwProcessId);
if(hProcess != NULL)
{
CONTEXT Context;
ZeroMemory(&Context, sizeof(Context));
Context.ContextFlags = CONTEXT_FULL;
if(::SuspendThread(hThread) != (DWORD)-1)
{
CONTEXT Context;
ZeroMemory(&Context, sizeof(Context));
Context.ContextFlags = CONTEXT_FULL;
if(::GetThreadContext(hThread, &Context))
{
DWORD64 dwImageBase = GetModuleBase(hProcess, GetIp(Context));
if(dwImageBase)
{
MINIDUMP_EXCEPTION_INFORMATION ExceptionInformation;
ZeroMemory(&ExceptionInformation, sizeof(ExceptionInformation));
ExceptionInformation.ThreadId = dwThreadId;
ExceptionInformation.ExceptionPointers = (EXCEPTION_POINTERS*)malloc(sizeof(EXCEPTION_POINTERS));
ExceptionInformation.ExceptionPointers->ContextRecord = ContextRecord;
ExceptionInformation.ExceptionPointers->ExceptionRecord = ExceptionRecord;
bSuccess = MiniDumpWriteDump(hProcess, dwProcessId, hDumpFile, MiniDumpWithDataSegs, &ExceptionInformation, NULL, NULL);
}
}
::ResumeThread(hThread);
}
::CloseHandle(hProcess);
}
return bSuccess;
}
二、如何使用crashdumps
crashdumps文件通常用于故障排查,可以分析文件中记录的信息找到软件崩溃的原因。当软件工作出现问题时,可以手动或者通过一些工具自动生成crashdumps。
Windows操作系统中提供了一些辅助程序可以生成crashdumps,例如procdump、ADPlus等工具。procdump 是一个轻量级的工具,它会在到达自定义的 CPU 利用率阈值或者发生异常时触发指定程序的崩溃记录( .dmp ),不影响目标应用程序的性能。
// 使用procdump生成Crash Dumps
procdump.exe -ma -e 1 myapp.exe myapp.dmp
// 解析Crash Dumps
windbg.exe -z myapp.dmp -y SymbolPath -c "!analyze -v; !clrstack;"
根据crashdumps信息可以定位到软件崩溃的位置和原因,进而修复问题。
三、crashdumps实践
在软件开发中,为了提高软件的鲁棒性和故障排查能力,可以自行编写代码来捕获生成crashdumps。以下是一个C++实现生成crashdumps的示例代码:
// C++代码示例
int main()
{
SetUnhandledExceptionFilter(CustomDumpFilter);
int* p = nullptr; // 故意造成异常,方便测试
*p = 1;
return 0;
}
LONG WINAPI CustomDumpFilter(_In_ struct _EXCEPTION_POINTERS* ExceptionInfo)
{
WCHAR szDumpPath[MAX_PATH] = { 0 };
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, szDumpPath)))
{
WCHAR szFileName[MAX_PATH] = { 0 };
SYSTEMTIME st = { 0 };
GetLocalTime(&st);
wsprintf(szFileName, L"crash-%04d%02d%02d-%02d%02d%02d.dmp",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
PathAppend(szDumpPath, szFileName);
HANDLE hFile = CreateFile(szDumpPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
exceptionInfo.ThreadId = GetCurrentThreadId();
exceptionInfo.ExceptionPointers = ExceptionInfo;
exceptionInfo.ClientPointers = FALSE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &exceptionInfo, NULL, NULL);
CloseHandle(hFile);
}
}
return EXCEPTION_EXECUTE_HANDLER;
}
在程序运行时,只需调用 SetUnhandledExceptionFilter 函数即可指定自定义的异常处理函数。当程序发生异常崩溃时,CustomDumpFilter 函数会被调用,该函数负责生成一个crashdumps文件并保存到指定位置。
四、总结
crashdumps是一种有效的故障排查工具,可以帮助程序员解决软件崩溃问题。本文详细介绍了crashdumps的概念、使用方法和代码实践,希望对大家有所帮助。