调试Release程序--Dump文件方式.doc_第1页
调试Release程序--Dump文件方式.doc_第2页
调试Release程序--Dump文件方式.doc_第3页
调试Release程序--Dump文件方式.doc_第4页
调试Release程序--Dump文件方式.doc_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

在Windows平台下用C+开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。因为release版本来就少了很多调试信息,更何况一般都是发布出去由用户使用,crash的现场很难保留和重现。目前有一些方法可以解决:崩溃地址 + MAP文件;MAP文件;SetUnhandledExceptionFilter + Minidump。本文重点解决Minidump方式。一、 Minidump文件生成 1、Minidump概念 minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在 系统属性 - 高级 - 启动和故障恢复 - 设置 - 写入调试信息 中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:WindowsMinidump路径下生成一个.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文件,即可实现需要的功能。生成dump文件类(minidump.h)#pragma once#include #include #include #pragma comment(lib, dbghelp.lib)inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)if(pModuleName = 0)return FALSE;WCHAR szFileName_MAX_FNAME = L;_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);if(wcsicmp(szFileName, Lntdll) = 0)return TRUE;return FALSE; inline BOOL CALLBACK MiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput)if(pInput = 0 | pOutput = 0)return FALSE;switch(pInput-CallbackType)case ModuleCallback: if(pOutput-ModuleWriteFlags & ModuleWriteDataSeg) if(!IsDataSectionNeeded(pInput-Module.FullPath) pOutput-ModuleWriteFlags &= (ModuleWriteDataSeg); case IncludeModuleCallback:case IncludeThreadCallback:case ThreadCallback:case ThreadExCallback:return TRUE;default:;return FALSE;/创建Dump文件inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if(hFile != NULL) & (hFile != INVALID_HANDLE_VALUE)MINIDUMP_EXCEPTION_INFORMATION mdei;mdei.ThreadId = GetCurrentThreadId();mdei.ExceptionPointers = pep;mdei.ClientPointers = FALSE;MINIDUMP_CALLBACK_INFORMATION mci;mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;mci.CallbackParam = 0;MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff;MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);CloseHandle(hFile); LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)return NULL;BOOL PreventSetUnhandledExceptionFilter()HMODULE hKernel32 = LoadLibrary(_T(kernel32.dll);if (hKernel32 = NULL)return FALSE;void *pOrgEntry = GetProcAddress(hKernel32, SetUnhandledExceptionFilter);if(pOrgEntry = NULL)return FALSE;unsigned char newJump 100 ;DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;dwOrgEntryAddr += 5; / add 5 for 5 op-codes for jmp farvoid *pNewFunc = &MyDummySetUnhandledExceptionFilter;DWORD dwNewEntryAddr = (DWORD) pNewFunc;DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;newJump 0 = 0xE9; / JMP absolutememcpy(&newJump 1 , &dwRelativeAddr, sizeof(pNewFunc);SIZE_T bytesWritten;BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);return bRet;LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)TCHAR szMbsFileMAX_PATH = 0 ;:GetModuleFileName(NULL, szMbsFile, MAX_PATH);TCHAR* pFind = _tcsrchr(szMbsFile, );if(pFind)*(pFind+1) = 0;_tcscat(szMbsFile, _T(CreateMiniDump.dmp);CreateMiniDump(pException,szMbsFile);/ TODO: MiniDumpWriteDumpFatalAppExit(-1, _T(Fatal Error);return EXCEPTION_CONTINUE_SEARCH;/运行异常处理void RunCrashHandler()SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);PreventSetUnhandledExceptionFilter();/测试实现文件/ 一个有函数调用的类/ class CrashTestpublic:void Test() Crash(); private:void Crash() / 除零,人为的使程序崩溃/int i = 13;int j = 0;int m = i / j;strcpy(NULL,adfadfg);int _tmain(int argc, _TCHAR* argv)/设置异常处理函数RunCrashHandler();CrashTest test;test.Test();getchar();return 0; 注意事项1、需要配置debug选项,在C/C+选项常规调试信息格式(设置为程序数据库(/Zi);在连接器选项调试生成调试信息(设置为是);C/C+选项优化禁用。(参见下图)2、 可执行文件(exe)必须找到dbghelp.dll,才能生成Dump文件。这个DLL可以从调试工具包中找到。3、*.exe、*.pdb、*.dump、dbghelp.dll 这四个文件需要放在同一目录下才好调试,双击dump文件时,就可以自动关联到出错代码位置。4、为了获取更多更深入的调试信息,需要把程序优化开关设置成禁用。5、当异常代码定位成功以后,如果无法阻止异常的产生,可以用 _try 结构包装异常代码,_try 和 try 不同,前者可以捕获非法指针产生的异常。_try / 会异常的函数_except( EXCEPTION_EXECUTE_HANDLER )/ 异常处理二、 调试Minidump文件1、双击minidump文件(*.dmp)。默认会启动vs2008。 2、菜单工具选项调试符号,增加PDB文件路径。(若minidump文件与pdb文件在同一目录,跳过此步) 3、若调试的程序需要微软基础库的PDB信息,可以增加一个路径为:http:/msdl.m

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论