我为一位客户开发了一个程序,他在做某项操作时正在体验。这并不总是发生在相同的位置和相同的数据上,而且,它既不会发生在我的本地开发机中,也不会发生在我的测试虚拟机中(它没有所有开发设备)。
鉴于这些条件,我决定使用MAP(在配置属性->链接器->带有选项/MAP的调试器中启用)进行编译,以查看哪个函数导致崩溃。
如果我正确理解,当程序崩溃时,我必须检查偏移错误,然后,在我的MAP中搜索列RVA+BASE:
Address Publics by Value Rva+Base Lib:Object
0001:00037af0 ?PersonalizzaPlancia@CDlgGestioneDatiProgetto@MosaicoDialogs@@IAEXXZ 00438af0 f DlgGestioneDatiProgetto.obj
0001:00038000 ?SalvaTemporanei@CDlgGestioneDatiProgetto@MosaicoDialogs@@IAEXXZ 00439000 f DlgGestioneDatiProgetto.obj
实际上,我的崩溃发生在offset:
00038C90
,所以我应该认为它在方法中的某个地方:
MosaicoDialogs::CDlgGestioneDatiProgetto::PersonalizzaPlancia
但这不是绝对可能的,所以假设计算机不可能出错,我就是那个做得不好的人。
有人能告诉我如何正确地阅读MAP吗?
不用麻烦了——相反,使用启用的符号构建项目并将它们剥离到PDB文件中。
稍微修改一下程序,当它使用未处理的异常处理程序崩溃时,写一个迷你转储
将新编译的程序交给客户,当它崩溃时调用MiniDumpWriteDump.
要求客户将这个。dmp文件发送给你,然后你只需在Visual Studio(或WinDbg)中加载它,它就会将符号与程序匹配,也会匹配代码。您应该能够看到确切的代码行和所涉及的一些变量。(如果使用VS,当你加载。dmp文件时,右上角会有一个"开始调试"选项,点击它,因为它会在崩溃点"开始调试")
首先在本地尝试-在程序的某个地方放置一个div by 0错误,看看是否可以在运行后调试转储。注意,您必须为程序的每次构建保持完全相同的符号文件——它们完全匹配。即使没有任何改变,也不能期望一个版本的符号文件与另一个版本匹配。
有关于这类事情的教程,例如来自CodeProject的这个教程,看起来它描述了您需要的内容。
这篇代码项目文章很好地解释了读取MAP文件以查找崩溃位置的方法。
http://www.codeproject.com/Articles/3472/Finding-crash-information-using-the-MAP-file希望帮助。
对于事后调试,有一种替代方法可以使不需要使用映射文件。相反,它需要您创建一个简单的注册表脚本来启用一些WER (Windows错误报告)标志来捕获崩溃转储文件。首先,使用调试符号构建应用程序。然后,按照收集用户模式转储的说明操作。基本上,您可以在"LocalDumps"键下创建一个子键。此子键必须是应用程序的名称,例如"myapplication.exe"。然后,创建"DumpCount"、"DumpType"one_answers"DumpFolder"键/值。让用户运行注册表脚本。这将启用在本地捕获转储。然后,让用户强制崩溃收集转储文件。然后,用户可以将转储文件发送给您,以便使用前面创建的符号进行调试。最后,您需要创建一个注册表脚本来删除您添加到注册表中的键/值。