您的位置:首页 > 其它

VS2010调试程序--Dump文件方式

2016-10-26 17:59 429 查看
dump文件,在VC中的调试还是非常非常非常有用的,因为我们也不会经每一行代码都加上日志,当然如果你愿意,也可以每一行都加上日志;

在Windows上,添加dump文件有两种方法:

方法一:一个是在程序中添加代码;

方法二:修改注册表(参考后面的bat文件写法,在win7上用管理员程序运行);建议用这个方法,方便实用;(http://blog.csdn.NET/hgy413/article/details/7586957#)

from:
http://blog.csdn href="http://lib.csdn.net/base/dotnet" target=_blank>.Net/byxdaz/article/details/25872151
http://blog.csdn.net/starlee/article/details/6630816
在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。因为release版本来就少了很多调试信息,更何况一般都是发布出去由用户使用,crash的现场很难保留和重现。目前有一些方法可以解决:崩溃地址 + MAP文件;MAP文件;SetUnhandledExceptionFilter + Minidump。本文重点解决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文件,即可实现需要的功能。
生成dump文件类(minidump.h)

[cpp] view
plaincopy





#pragma once

#include <windows.h>

#include <imagehlp.h>

#include <stdlib.h>

#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, L"ntdll") == 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 far

void *pNewFunc = &MyDummySetUnhandledExceptionFilter;

DWORD dwNewEntryAddr = (DWORD) pNewFunc;

DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;

newJump[ 0 ] = 0xE9; // JMP absolute

memcpy(&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 szMbsFile[MAX_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: MiniDumpWriteDump

FatalAppExit(-1, _T("Fatal Error"));

return EXCEPTION_CONTINUE_SEARCH;

}

//运行异常处理

void RunCrashHandler()

{

SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);

PreventSetUnhandledExceptionFilter();

}

//测试实现文件
// 一个有函数调用的类
//
class CrashTest
{
public:
void Test()
{
Crash();
}

private:
void Crash()
{
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文件

双击minidump文件(*.dmp)。默认会启动vs2008。
菜单Tools/Options, Debugging/Symbols,增加PDB文件路径。注:如果minidump文件与pdb文件在同一目录,就不用设置这个了。
若调试的程序需要微软基础库的PDB信息,可以增加一个路径为:
http://msdl.microsoft.com/download/symbols
在界面下方Cache Symbol From symbol…选择本地存储这些Symbols的路径。 注:如果本地已存储过微软基础库的pdb,就直接按照此步操作设置本地路径,不必执行上一步操作了。


设置代码路径:

设置代码路径:
刚打开的dmp工程,进入解决方案的属性。在这里输入源程序的代码路径。注:一定是sln所在的路径,而不是vcproj的路径!



按F5,debug吧。

demo代码下载:http://download.csdn.net/detail/byxdaz/7349325

//-

#pragma once

#include <windows.h>

#include <imagehlp.h>

#include <stdlib.h>

#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, L"ntdll") == 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 far

void *pNewFunc = &MyDummySetUnhandledExceptionFilter;

DWORD dwNewEntryAddr = (DWORD) pNewFunc;

DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;

newJump[ 0 ] = 0xE9; // JMP absolute

memcpy(&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 szMbsFile[MAX_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: MiniDumpWriteDump

FatalAppExit(-1, _T("Fatal Error"));

return EXCEPTION_CONTINUE_SEARCH;

}

//运行异常处理

void RunCrashHandler()

{

SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);

PreventSetUnhandledExceptionFilter();

}

调试方法不用上述那么麻烦,直接在Debug目录下 或者 Release目录下 exe + pdb + dmp 在同一目录,然后双击dmp文件VC2010就可以打开,然后点击右上角的调试按钮就可以直接定位到崩溃的代码了;

参考这里: http://blog.csdn.net/starlee/article/details/6630816
别人机器上的dump调试:
http://blog.csdn.net/xhk456/article/details/7523150
这段时间突然发现,要一下做一个金刚不坏之身的程序是不太可能滴,至于对我来说吧。

这个程序也要经过千锤百炼才能够练就一个强大的自信心。

我现在做系统就不考虑一下把程序做的足够强壮了,因为我也做不到

,现在做系统时,总考虑的一个问题:
当系统异常的时候怎么去处理?

我不怕系统程序出现异常,甚至直接Over,只要能在异常时处理异常后继续运作,在崩溃重启后能够继续把没
干的活给干了,那么这个在我能够承受的范围内,也在大多数客户的承受范围内,因为这样就是我们所说的将
损失减小到最低,其实是不是最低只有自己能够知道。

当然了,我更希望能够做出一个健壮无比的牛逼程序,所以我想知道程序是在什么情况下崩溃的,可是有些问题
你懂的,老在客户机器上或者生产环境下出现,却在自己的机器上和测试环境就他妈的不出现,遇见这种情况我是
跳楼或者杀人的心情都有了,偶尔我也犯过情绪,想提出辞职申请,换个行业去,告别这苦逼的程序员生涯,
可总不知道是什么力量支持着我,让我坚强依旧滴做着程序员,过着狗日的日子。

后来,不经意间,一位同事给我说了一个种在系统中异常或者崩溃的时候,来生成dump文件,然后用调试器来调试。
这样就可以在生产环境中的dmp文件,拷贝到自己的开发机器上,调试就可以找到错误的位置,配合程序调试符号pdb文件,
直接可以定位到源代码中位置,真是太他妈的神奇了,虽然Release版本下的很多变量的值是不对滴,但并不影响我这个
这么有执着心的coder来找bug。

同事给了我他写的示例,往空指针拷贝数据,在非调试下运行后,果然的崩了,果断滴生成了一个扩展名为dmp的文件,
然后他用vs2010打开那个dmp文件,vs2010很果断滴定位到了那个往空指针拷贝数据那里。
看他那娴熟的操作,顿时感觉到了他的强大和微软的牛逼。

后来我就学他,在程序中加入程序异常时产生dump文件的功能,待系统发布后,在一次不经意间一个程序挂掉了。
在客户的谩骂中,我面带笑容说:这个问题很好解决。我满怀信心滴从服务器上拷贝了程序崩溃产生dump文件,
然后学着那个同事用vs2010打开,我了个去,咋没有定位到源代码中内,只定位到了可执行文件的一个地址,这让哥
情何以堪呐!



还好,我对pdb了解还比较熟悉,想来应该是符号文件的问题,于是就开始摸索的,不经意见的在
堆栈处右击了下,发现菜单里竟然有“加载符号”,而且还有“符号路径”,我想这大概就是让我来选择
对应的pdb文件吧,顿时感觉曙光就在前面。



点击了“符号路径”后如下图:



才发现了,它并不是来选择符号文件,而是选择对应的可执行程序的路径,选择了后果断滴定位到了源代码的位置,
才发现一个很简单很美丽的bug,修改后,在测试后重现发布,系统的健壮性又提高了一个台阶。

回头想了想,我同事给我演示的时候,他程序运行的目录和就是他直接用vs2010生成的目录,所以此种情况下
用vs2010打开dmp文件即可定位到源代码文件。而发布后的程序,一般情况下你根本不知道别人放在什么地方去执行的,
因此调试时还并必须选相同版本的可执行文件,然后pdb文件才会好好工作,要不没可执行文件,咋个调试嘛。

哎,这同事,居然还留了一手,坑爹啊。

不过还是要感谢他滴,我又掌握了一些东西,又增强了我这个苦逼程序员写好程序的信心。

在写这个之前看了相关文章,感觉比较好的推荐一哈:
http://www.cppblog.com/woaidongmao/archive/2011/05/10/146086.html

到这里,你就可以在你的工程中通过代码的方式添加,在程序崩溃的时候回创建dump文件了;

.dump

.dump 命令创建一个用户模式或内核模式崩溃转储文件。分析工具:https://msdn.microsoft.com/en-us/library/windows/desktop/ee416349(v=vs.85).aspx#writing_a_minidump
程序崩溃(crash)的时候, 为了以后能够调试分析问题, 可以使用WinDBG要把当时程序内存空间数据都保存下来,生成的文件称为dump 文件。 步骤:
1) 打开WinDBG并将之Attach 到crash的程序进程
2) 输入产生dump 文件的命令
直接用.dump -?可以看到它的简单说明:

[cpp] view
plaincopy

0:000> .dump -?

Usage: .dump [options] filename

Options are:

/a - Create dumps for all processes (requires -u)

/b[a] - Package dump in a CAB and delete dump

/c <comment> - Add a comment (not supported in all formats)

/j <addr> - Provide a JIT_DEBUG_INFO address

/f - Create a legacy style full dump

/m[acdfFhiprRtuw] - Create a minidump (default)

/o - Overwrite any existing file

/u - Append unique identifier to dump name

/o :覆盖具有相同名字的dump文件。如果没有使用该选项又存在一个相同名字的文件,则dump文件不会被写入:比如我的C盘原有一个myapp.dmp文件:

[cpp] view
plaincopy

0:000> .dump c:/myapp.dmp

Unable to create file 'c:/myapp.dmp' - Win32 error 0n80

"文件存在。"

0:000> .dump /o c:/myapp.dmp

Creating c:/myapp.dmp - mini user dump

Dump successfully written

/f (用户模式:) 创建一个完整用户模式dump,这里要注意不要字面理解,
完整用户模式dump是基本的用户模式dump文件。这种dump文件包含进程的完整内存空间、程序本身的可执行映像、句柄表和其他对调试器有用的信息

注意 和名字无关,最大的"minidump"文件实际上可以提供比完整用户模式dump更多的信息。例如,.dump /mf.dump /ma将创建比.dump /f更大更完整的文件。
用户模式下,使用.dump /m[MiniOptions] 是最好的选择。通过这个开关创建的dump文件可以很小也可以很大。通过指定合适的MiniOptions 可以控制究竟需要包含哪些信息。

[cpp] view
plaincopy

0:000> .dump /o/f c:/myapp.dmp

*****************************************************************************

* .dump /ma is the recommend method of creating a complete memory dump *

* of a user mode process. *

*****************************************************************************

Creating c:/myapp.dmp - user full dump

Dump successfully written

我们看到了,系统给出了提示:.dump /ma是创建完整dump的推荐方式(用户模式下)

/m[MiniOptions] 创建一个小内存dump(内核模式)或者 minidump (用户模式)。如果没有指定 /f /m/m 是默认选项。用户模式下,/m 后面可以跟附加的MiniOptions 用来指定dump文件中包含的数据。如果没有使用MiniOptions ,dump文件包含模块、线程和调用堆栈信息,但是没有其他附加信息
MiniOption作用
a创建一个包含所有附加选项的minidump。/ma选项相当于/mfFhut —它会在minidump中添加完整的内存数据、句柄数据、已卸载模块信息、基本内存信息和线程时间信息。
f在minidump中包含完整内存数据。目标程序拥有的所有 可访问的已交付的页面(committed pages)都会包含进去。
F在minidump中添加所有基本内存信息。这会将一个流加入到包含完整基本内存信息的minidump中,而不单是可使用的内存。这样可以使得调试器能够重建minidump生成时进程的完整虚拟内存布局。
h在minidump中包含和目标进程相关的句柄信息。
u在minidump中包含已卸载模块信息。仅在Windows Server 2003和之后版本的Windows中可用。
t在minidump中包含附加的线程信息。包括可以在调试minidump时使用!runaway扩展命令或.ttime (Display
Thread Times)
命令进行显示的线程时间。
i在minidump中包含次级内存(secondary memory)。次级内存是由堆栈中的指针或备份存储(backing store)中引用到的任何内存,加上该地址周围的一小段区域。
p在minidump中包含进程环境块(PEB)和线程环境块(TEB)。这在想访问程序的进程和线程相关的Windows系统信息时很有用。
w将所有已交付的可读写的私有页面包含进minidump。
d在minidump中包含可执行映像中所有可读写的数据段。
c加入映像中的代码段。
r从minidump中去掉对重建调用堆栈无用的堆栈和存储内存部分。局部变量和其他数据类型值也被删除。这个选项不会使得minidump变小(因为这些内存节仅仅是变成0),但是当想保护其他程序中的机密信息时有用。
R在minidump中去掉完整的模块路径。仅包含模块名。如果想保护用户的目录结构时该选项有用。
选项(1): /m
命令行示例:.dump /m C:/dumps/myapp.dmp
注解: 缺省选项,生成标准的minidump, 转储文件通常较小,便于在网络上通过邮件或其他方式传输。 这种文件的信息量较少,只包含系统信息、加载的模块(DLL)信息、 进程信息和线程信息。
选项(2): /ma
命令行示例:.dump /ma C:/dumps/myapp.dmp
注解: 带有尽量多选项的minidump(包括完整的内存内容、句柄、未加载的模块,等等),文件很大,但如果条件允许(本机调试,局域网环境), 推荐使用这中dump。
选项(3):/mFhutwd
命令行示例:.dump /mFhutwd C:/dumps/myapp.dmp
注解:带有数据段、非共享的读/写内存页和其他有用的信息的minidump。包含了通过minidump能够得到的最多的信息。是一种折中方案。
Fhutwd按字母对应上面的MiniOptions表示

//-xp自动生成dump-----------------------------------------------------------------------------------------------------------------------------------------------------------------
那怎么自动生成dump文件呢,比如对方的电脑没有windbg,这里用到一个window XP系统自带工具,Dr.Watson
运行方式很简单:
直接run-输入drwtsn32 -i就可以了,会提示这样的:



这个命令真难记,实话,记华生医生吧,福尔摩斯中的
如果有程序崩溃,会自动生成dump,这时再输入drwtsn32就会运行这个程序:



找到对应路径的DMP文件就行了,一般放在如下路径:

C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson

//-win7自动生成dump-----------------------------------------------------------------------------------------------------------------------------------------------------------------
win7下需打开regedit--> 找到:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting]

在它下面加一项LocalDumps,并做如下项配置:

Value描述Type默认值
DumpFolder文件保存路径REG_EXPAND_SZ%LOCALAPPDATA%CrashDumps
DumpCountdump文件的最大数目REG_DWORD10
DumpType指定生成的dump类型:

0:Custom dump

1:Mini dump

2:Full dump
REG_DWORD1
CustomDumpFlags仅在DumpType为0时使用

为MINIDUMP_TYPE的组合
REG_DWORD
MiniDumpWithDataSegs|
MiniDumpWithUnloadedModules|
MiniDumpWithProcessThreadData
可以写成.bat:

[cpp] view
plaincopy


@echo off

echo 设置Dump...

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps"

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d "C:\MyDump" /f

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f

echo Dump已经设置

pause

@echo on

[cpp] view
plaincopy


@echo off

echo 正在取消设置Dump...

reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /f

echo Dump已经取消设置

pause

@echo on

LocalDumps是全局的,如果想针对指定进程单独设置,如test1.exe,则在/LocalDumps下新建子项test1.exe,同时在test1目录下复制上表的选项,这样,系统就会先读全局设置,再读子项test1.exe的设置
简单测试:
void CtMFC5Dlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知处理程序代码

char * pstr = NULL;
int n = strlen( pstr );
}

在Windows 7上可以由多个方法产生dump文件:
转一篇文章:
Windows调试
- 如何使用dump文件

如何使用dump文件
我最近在开发一个windows下的程序(win7/win8),有一些case下会crash,如果在自己开发机器上调试比较简单:运行程序,然后vs attach到进程上即可,但是在每台QA的机器上安装vs时不现实的,因此我们要用到dump文件。
微软网站有一篇文章讲述如何创建dump文件:
http://support.microsoft.com/kb/931673 第一种: 通过任务管理器:这种适用在程序挂了(crash)的时候进程还未退出,比如我运行程序,出现了下面的错:



此时打开任务管理器,右击相应进程,点击"Create Dump File“:



一会创建完成:



然后把这个DMP文件拷到开发机器上,用VS打开: 会出现下面的界面,要想知道发生错误时候的调用栈,需要设置symbol的路径,点击”Set Symbol Paths“:



注意这个pdb要对应于crash的exe,否则调用栈没法显示:



设置完成后,点击”Debug with Native Only“ 你就可以看到调用栈了。

第二种: 改注册表
如果程序crash的时候没有框蹦出来,可以通过改注册表的设置让操作系统在程序crash的时候自动生成dump,并放到特定的目录下

[plain] view
plaincopy

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps

Value Name = DumpType

Data type: REG_DWORD

Value Data = 1

其中Value Data=1代表的含义是:

[plain] view
plaincopy

0 = Create a custom dump

1 = Mini dump

2 = Full dump

设置完成后,crash发生时,操作系统生成dump,路径在%LOCALAPPDATA%\CrashDumps下,详细可以参考:
http://msdn.microsoft.com/en-us/library/bb787181%28v=VS.85%29.aspx (完)
http://blog.csdn.net/chinabinlang/article/details/49491813
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: