我有一个巨大的应用程序(在PowerBuilder中制作),每隔一段时间崩溃一次,所以很难重现这个错误。我们设置了它,这样当发生这样的崩溃时,我们会收到一个.dmp文件。
我使用WinDbg分析我的.dmp使用命令"!analyze -v
. conf"创建文件。由此我可以推断出发生的错误是访问违规C0000005。根据[0]和[1]参数,它试图解引用一个空指针。
WinDbg还向我展示了由大约30行组成的STACK_TEXT,但我不确定如何阅读它。根据我所看到的,我需要使用一些符号。
我的STACK_TEXT第一行是这样的:
00000000`00efca10 00000000`75d7fa46 : 00000000`10df1ae0 00000000`0dd62828 00000000`04970000 00000000`10e00388 : pbvm!ob_get_runtime_class+0xad
从这里,我的目标是分析这个文件,找出这个错误发生在程序中的确切位置或它在哪个函数中。这是我将能够在进一步分析堆栈跟踪后找到的东西吗?
我怎么能查明在哪里程序崩溃发生使用。dmp和WinDbg,所以我可以修复我的代码?
如果使用!analyze -v
分析崩溃转储,则STACK TEXT
之后的行是堆栈跟踪。如果设置了正确的线程和上下文,输出相当于kb
。
kb
的输出为
- 返回地址
- 堆栈上的前4个值
反引号`
告诉你你在64位运行,他们在中间分割64位值。
在32位上,堆栈上的前4个参数通常相当于函数的前4个参数,具体取决于调用约定。
在64位上,堆栈不再那么相关,因为在64位调用约定中,参数通过寄存器传递。因此,您可以忽略这些值。
有趣的部分是符号像pbvm!ob_get_runtime_class+0xad
。!
前面是模块名称,通常是DLL或EXE名称。寻找你创造的东西。!
之后和+
之前是一个方法名。+
后面是距离函数开始的偏移量,以字节为单位。
只要你没有数千行代码的函数,这个数字应该很小,像<0 x200型。如果这个数字比这个大,通常意味着你没有正确的符号。在这种情况下,方法名不再可靠,因为它可能只是最后一个已知的(最后导出的)方法名,并且从那里走了很远的路,所以不要相信它。
在pbvm!ob_get_runtime_class+0xad
的情况下,pbvm
是DLL名,ob_get_runtime_class
是方法名,+0xad
是指令指针所在方法内的偏移量。
对我(对PowerBuilder一无所知)来说,PBVM听起来像PowerBuilder虚拟内存的DLL实现。这不是你的代码,这是Sybase编译的代码。你需要在调用堆栈中进一步查找DLL中的错误代码。
在阅读维基百科之后,似乎PowerBuilder并不一定编译成本机代码,而是编译成中间的p代码。在这种情况下,您可能不太幸运,因为您的代码从未真正在调用堆栈上,并且您需要一个特殊的调试器或WinDbg扩展(可能不存在,如Java)。使用-pbdebug
命令行开关运行它,或者将其编译为本机代码,然后让它再次崩溃。