我有一个客户正在获得100%可重现的崩溃,我无法在我在Visual Studio 2005中编译的程序中复制。我向他们发送了我的程序的调试版本并保留了所有PDB和DLL文件。他们给我发了minidump文件,但当我打开它时,我得到了:
“MiniDump.dmp中0x00000000处的未处理异常:0xC0000005:访问冲突读取位置0x00000000。”
然后调用堆栈只显示“0x00000000()”,反汇编显示内存转储为0x0。我已经设置了符号服务器,加载了我的PDB符号等。但是我看不出有什么方法可以知道哪些DLL实际上导致跳转为null。这是一个包含许多依赖项的大型项目,其中一些是我没有源代码或PDB的二进制文件,因为我使用API作为第三方。
那么这个minidump究竟有用吗?如何查看导致崩溃的DLL?我以前从来没有真正使用minidump进行调试,但我读过的所有教程似乎至少都显示了一个函数名或其他能给你一个调用堆栈线索的东西。我只得到一行指向null。
我还尝试使用“Depends”来查看是否存在未解析的DLL依赖项;但是在我使用各种Windows操作系统的三台测试机器上,我似乎得到了三套不同的OS DLL依赖项(但却无法复制崩溃);所以这对于诊断问题似乎不是一种特别可靠的方法。
有哪些其他方法可用于确定此问题的原因?有没有办法退回一条指令,看看哪个DLL跳转到空?
答案 0 :(得分:5)
看起来这个例子中的答案是“使用WinDbg而不是Visual Studio来调试minidump”。我无法从VS中获得任何有用的信息,但是WinDbg给了我关于导致崩溃的函数调用链的大量信息。
在这种情况下,它仍然没有帮助解决我的问题,因为所有的功能都在我正在使用的第三方库中,所以看起来我的具体问题的唯一明确答案是使用日志文件来跟踪我的申请状态导致崩溃。
我想如果其他人在调试minidump时看到类似的问题与无用的调用堆栈,最好的做法是使用WinDgb而不是Visual Studio打开它。似乎很奇怪,这项工作的最佳工具是免费的Microsoft产品,而不是商业产品。
这里的另一个教训可能是“任何使用第三方库的程序都需要编写日志文件”。
答案 1 :(得分:2)
所有“简单”的事后调试方法背后的整个想法是捕获堆栈跟踪。如果您的应用程序覆盖了堆栈,则无法进行此类分析。只有非常复杂的方法才能在专用硬件中记录整个程序执行情况。
在这种情况下的方法是日志文件。在发生故障的区域周围传播一些日志语句,并将该版本传输给客户。崩溃后,您将在日志文件中看到最后一条日志语句。在该点与未记录在日志文件中的下一个日志语句之间添加更多日志语句,再次发布该版本。重复,直到找到导致问题的线。
我在ddj.com上写了两篇关于此的文章:
答案 2 :(得分:0)
只是观察,但堆栈被截断或覆盖,这可能是使用未初始化字段或缓冲区溢出的简单情况吗?
这可能相当容易找到。
答案 3 :(得分:0)
您是否尝试在客户的计算机上设置WinDbg并将其用作导致崩溃的任何应用程序的默认调试程序?您只需将pdb文件添加到应用程序所在的文件夹即可。当粉碎发生时,WinDbg启动,你可以尝试获取调用堆栈。
答案 4 :(得分:0)
可能你已经知道了这一点,但这里有一些关于minidump调试的观点: 1.您需要具有完全相同的可执行文件和PDB文件,就像在创建minidump的客户端计算机上一样,它们应该完全放在相同的目录中。只是重建相同的版本没有帮助。 2.调试器必须连接到MS Symbols服务器。 3.调试器启动时,它会在“输出”窗口中打印进程加载日志。通常,应该使用调试信息成功加载所有库。也会加载没有调试信息的库,但会打印“无调试信息”。学习这个日志 - 它可以为您提供一些信息。
如果可执行堆栈包含来自库的帧而没有调试信息,则可能不会显示。例如,如果您的代码作为第三方库回调运行,则会发生这种情况。
尝试在您自己的计算机上创建minidump,添加一些创建未处理异常的代码,并立即调试它。这有用吗?比较成功和不成功调试会话中的加载日志。
答案 5 :(得分:0)
您可能已调用空函数指针。需要当前执行的功能信息来显示调用栈信息。强制设置指令指针以启动任何简单函数,然后您将再次看到调用堆栈信息。
void SimpleFunc()
{ // <- set next statement here
}