KB:Visual C++
Q196755 - HOWTO: Determine the Location of a Crash
如何定位程序崩溃的地方
概述
本文档说明如何根据错误消息中的地址来找到错误发生的地方。例如,某个用户报告使用RELEASE版程序时发生崩溃,唯一的信息就是发生错误的地址。
【技巧一:使用MAP文件】
通过使用MAP文件,你可以定位包含错误代码的函数。要产生MAP文件,就要在工程选项中打开"/MAP"链接开关值,其设置步骤如下:
1、打开工程选项设置,设置RELEASE的选项。
2、选择"Link"页的"General"节,选择"Generate debug info"。
3、重新编译程序。
举例来说,假设错误信息如下:
testcrash.exe - Application Error
The instruction at "0x004011a9" referenced memory at "0x00000000". The
memory could not be "written"
错误地址为0x004011a9,检查MAP文件中的"Rva+Base"值(函数的起始位置),找到最匹配的位置。假设MAP文件内容如下:
<... lines removed ...>
Address Publics by Value Rva+Base Lib:Object
0001:00000000
?_GetBaseMessageMap@CTestcrashApp@@KGPBUAFX_MSGMAP@@XZ 00401000 f
testcrash.obj
0001:00000010 ?GetMessageMap@CTestcrashApp@@MBEPBUAFX_MSGMAP@@XZ
00401010 f testcrash.obj
0001:00000020 ??0CTestcrashApp@@QAE@XZ 00401020 f
testcrash.obj
0001:00000080 ??_ECTestcrashApp@@UAEPAXI@Z 00401080 f
testcrash.obj
0001:00000080 ??_GCTestcrashApp@@UAEPAXI@Z 00401080 f
testcrash.obj
0001:00000170 ?InitInstance@CTestcrashApp@@UAEHXZ 00401170 f
testcrash.obj
0001:00000210 ??1CTestcrashDlg@@UAE@XZ 00401210 f
testcrash.obj
0001:00000260 ?Serialize@CObject@@UAEXAAVCArchive@@@Z 00401260 f
testcrash.obj
<... lines removed ...>
我们发现,函数?InitInstance@CTestcrashApp@@UAEHXZ的起始地址为00401170,下一个函数??1CTestcrashDlg@@UAE@XZ的起始地址,错误地址0x004011a9位于两者之间,那么可以断定错误出现在函数InitInstance中。
使用MAP文件可以定位错误函数,但是它不能将范围缩小到发生错误的语句。
【技巧二:使用PDB文件】
使用PDB文件可以准确定位错误发生的语句,其设置步骤如下:
1、保存在技巧一里面生成的MAP文件。
2、打开工程选项设置,设置RELEASE的选项。
3、选择"C/C++"页的"General"节,在"Debug Info"中选择"Program Database" ( 缺省为NULL )。
4、选择"Link"页的"General"节,选择"Generate debug info"。
5、选择"Link"页的"Customize"节,选择"Use program database"。
6、重新编译程序。
7、用Windiff或FC对照新产生的MAP文件和前面产生的MAP文件。
8、比较问题函数的"Rva+Base"是否发生变化,如果没有变化,跳过步骤9。
9、计算"Rva+Base"的差值,然后用这个值去修正错误地址,这样才得到新执行文件中的地址。
现在你就有了一个PDB文件,它可以用来决定错误发生的具体位置,步骤如下:
1、在VC里面打开工程
2、按F11单步执行程序
3、按ALT+F9打开断点对话框
4、以错误的地址设置一个断点(注意:地址前面要加0x)
5、打开包含错误函数的文件,这时你就能看到断点所在就是错误的语句。
【参考】
想了解调试技巧的更多内容,请参看VC在线文档中的“Using Visual C++ -- VC++ User's Guide -- Debugger”节。