当前位置:   article > 正文

Crash -- 生成Minidump调试信息_崩溃如何生成mini dangp

崩溃如何生成mini dangp

在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。因为release版本来就少了很多调试信息,更何况一般都是发布出去由用户使用,crash的现场很难保留和重现。目前有一些方法可以解决:

崩溃地址 + MAP文件;MAP文件;

SetUnhandledExceptionFilter + Minidump。


本文重点解决Minidump方式。



 1、Minidump概念
        minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在系统属性 -> 高级 -> 启动和故障恢复 -> 设置 -> 写入调试信息中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。
        我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性,dump文件是压缩过的。


2、生成minidump文件
        通过drwtsn32、NTSD、CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD、CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD、CDB等调试工具。根据MiniDumpWriteDump接口,完全可以程序自动生成Dump文件。


 


3、  自动生成Minidump文件
        当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。MSDN中描述为:


Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.


 因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在系统属性 -> 高级 -> 启动和故障恢复 -> 设置 -> 写入调试信息中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。

        我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性,dump文件是压缩过的。


2、生成minidump文件
通过drwtsn32、NTSD、CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD、CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD、CDB等调试工具。根据MiniDumpWriteDump接口,完全可以程序自动生成Dump文件。


3、  自动生成Minidump文件
当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。MSDN中描述为:

        Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.

        因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。

新建工程


下一步


下一步


Minidmp.h 

  1. #pragma once
  2. #include <windows.h>
  3. #include <imagehlp.h>
  4. #include <stdlib.h>
  5. inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName);
  6. inline BOOL CALLBACK MiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput);
  7. //创建Dump文件
  8. inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName);
  9. LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
  10. BOOL PreventSetUnhandledExceptionFilter();
  11. LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException);
  12. //运行异常处理
  13. void RunCrashHandler();

Minidmp.cpp 

  1. #include "stdafx.h"
  2. #include "Minidmp.h"
  3. #pragma comment(lib, "dbghelp.lib")
  4. inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
  5. {
  6. if(pModuleName == 0)
  7. {
  8. return FALSE;
  9. }
  10. WCHAR szFileName[_MAX_FNAME] = L"";
  11. _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
  12. if(wcsicmp(szFileName, L"ntdll") == 0)
  13. return TRUE;
  14. return FALSE;
  15. }
  16. inline BOOL CALLBACK MiniDumpCallback(PVOID pParam,
  17. const PMINIDUMP_CALLBACK_INPUT pInput,
  18. PMINIDUMP_CALLBACK_OUTPUT pOutput)
  19. {
  20. if(pInput == 0 || pOutput == 0)
  21. return FALSE;
  22. switch(pInput->CallbackType)
  23. {
  24. case ModuleCallback:
  25. if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
  26. if(!IsDataSectionNeeded(pInput->Module.FullPath))
  27. pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
  28. case IncludeModuleCallback:
  29. case IncludeThreadCallback:
  30. case ThreadCallback:
  31. case ThreadExCallback:
  32. return TRUE;
  33. default:;
  34. }
  35. return FALSE;
  36. }
  37. //创建Dump文件
  38. inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
  39. {
  40. HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  41. if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
  42. {
  43. MINIDUMP_EXCEPTION_INFORMATION mdei;
  44. mdei.ThreadId = GetCurrentThreadId();
  45. mdei.ExceptionPointers = pep;
  46. mdei.ClientPointers = FALSE;
  47. MINIDUMP_CALLBACK_INFORMATION mci;
  48. mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
  49. mci.CallbackParam = 0;
  50. MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff;
  51. MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);
  52. CloseHandle(hFile);
  53. }
  54. }
  55. LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
  56. {
  57. return NULL;
  58. }
  59. BOOL PreventSetUnhandledExceptionFilter()
  60. {
  61. HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
  62. if (hKernel32 == NULL)
  63. return FALSE;
  64. void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
  65. if(pOrgEntry == NULL)
  66. return FALSE;
  67. unsigned char newJump[ 100 ];
  68. DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
  69. dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
  70. void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
  71. DWORD dwNewEntryAddr = (DWORD) pNewFunc;
  72. DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
  73. newJump[ 0 ] = 0xE9; // JMP absolute
  74. memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
  75. SIZE_T bytesWritten;
  76. BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
  77. return bRet;
  78. }
  79. LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)
  80. {
  81. TCHAR szMbsFile[MAX_PATH] = { 0 };
  82. ::GetModuleFileName(NULL, szMbsFile, MAX_PATH);
  83. TCHAR* pFind = _tcsrchr(szMbsFile, '\\');
  84. if(pFind)
  85. {
  86. *(pFind+1) = 0;
  87. _tcscat(szMbsFile, _T("CreateMiniDump.dmp"));
  88. CreateMiniDump(pException,szMbsFile);
  89. }
  90. // TODO: MiniDumpWriteDump
  91. FatalAppExit(-1, _T("Fatal Error"));
  92. return EXCEPTION_CONTINUE_SEARCH;
  93. }
  94. //运行异常处理
  95. void RunCrashHandler()
  96. {
  97. SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
  98. PreventSetUnhandledExceptionFilter();
  99. }

CrashTest.h 

  1. #pragma once
  2. #include "Minidmp.h"
  3. class CCrashTest
  4. {
  5. public:
  6. CCrashTest(void);
  7. ~CCrashTest(void);
  8. public:
  9. void Test();
  10. private:
  11. void Crash();
  12. };

CrashTest.cpp 

  1. #include "StdAfx.h"
  2. #include "CrashTest.h"
  3. CCrashTest::CCrashTest(void)
  4. {
  5. }
  6. CCrashTest::~CCrashTest(void)
  7. {
  8. }
  9. void CCrashTest::Test()
  10. {
  11. Crash();
  12. }
  13. void CCrashTest::Crash()
  14. {
  15. // 除零,人为的使程序崩溃
  16. //
  17. int i = 13;
  18. int j = 0;
  19. //int m = i / j;
  20. strcpy(NULL,"adfadfg");
  21. }


CrashMinidumpTest.cpp 

  1. // CrashMinidumpTest.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include "CrashTest.h"
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7. //设置异常处理回调函数
  8. RunCrashHandler();
  9. CCrashTest test;
  10. test.Test();
  11. getchar();
  12. return 0;
  13. }

配置工程目录



下一步


下一步


下一步


下一步


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/179270
推荐阅读
  

闽ICP备14008679号