不匹配的符号是完整显示塞子还是我可以信任它们部分提取线索?

时间:2016-07-13 21:48:20

标签: c++ windbg

我没有正确的符号文件(Pdbs)所以我使用.reload /f /i加载我重新生成的内容而忽略了时间戳。我的项目有很多模块,这确实加载了其中一些而不是其他模块,我不知道为什么不是全部。

但是,我想知道如果有任何问题,我可以信任多少不匹配符号文件。这是来自故障转储文件的异常信息

0:000> .exr -1
ExceptionAddress: 020b1143 (Db!CDbaAdoRecordset::CDbaAdoRecordset+0x00000073) [abc.cpp @80]
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 00000004
Attempt to read from address 00000004

我是否应该合理地确定至少崩溃是在Db模块中?我是否还可以相信崩溃与它所说的相同的fil ename(abc.cpp)?当它显示我可以在代码[包括函数名称]中实际看到的实际函数时,调用堆栈更可能是正确的吗?

我知道符号和行号来自pdb文件,所以它可能有问题,但崩溃转储文件在所有这些连接中有什么作用,我可以用它来缩小问题范围?

我正在尝试从不匹配的符号文件中提取任何潜在客户或有用的信息。

更新

我正在调试产生转储崩溃的相同版本的代码。由于我们不这样做,因此可以完全排除诸如模块,类名或文件名之类的事情。从理论上讲,我调试的版本与崩溃版本完全匹配,因为它的版本受控制。

2 个答案:

答案 0 :(得分:3)

对于没有pdb文件的版本,我必须多次执行相同的操作。

您的构建环境越接近用于构建二进制文件的环境,您就会拥有更好的运气。确保您拥有用于构建二进制文件的确切源代码,编译器版本和编译器/链接器标志将使您的生活更轻松。有时你会很幸运,符号会如此接近,你甚至不会发现任何奇怪的事情。

  

我是否应该合理地确定至少崩溃是在Db模块中?

这是你唯一能确定的事情。实际上你没有符号就有这些信息。 (没有符号,它往往会显示一个带有大偏移的导出符号,如Db!DllMain+0x123456。在这种情况下,您仍然可以相信该模块是正确的。)

  

我是否还可以相信崩溃与它所说的文件名(abc.cpp)相同?

不。您现在的工作是验证您看到的所有

要验证的事项:

  • 在查看callstack时,源代码是否显示在该函数体中某处调用下一帧的函数?如果是这样,那么它很有可能是正确的。如果没有,如果内联函数调用,它仍然可能是正确的。

  • 在顶部框架,ExceptionAddress处的反汇编看起来像是编译器应该为符号指向的源代码生成的内容吗? (例如:我希望CDbaAdoRecordset的构造函数调用与RecordSets相关的方法,如CoCreateInstance(/*...*/, __uuidof(Recordset), /*...*/);

事实上,您知道符号文件中的内容(函数名称,行号等)应该让您了解您正在查看的内容以及可能出现的问题。

您最好的选择是从正常开始调试开始,即使您有匹配的符号...... Attempt to read from address 00000004 它可能试图访问一个空的对象上的偏移量4。那个对象是什么?一帆风顺!

答案 1 :(得分:3)

异常记录中的大多数内容与PDB无关,只会尝试将异常地址解析为调用堆栈。

我不确定WinDbg是否会为模块名称不匹配的DLL加载PDB。此外,我不太可能重命名DLL,我会说。

因此,您可以从具有不匹配的PDB的异常记录中信任的事项是:

ExceptionAddress: 020b1143 (Db!
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 00000004
Attempt to read from address 00000004

你不能信任的事情:

!CDbaAdoRecordset::CDbaAdoRecordset+0x00000073) [abc.cpp @80]
  

当它显示我在代码[包括函数名称]中实际可以看到的实际函数时,调用堆栈更有可能是正确的吗?

没有。这可能是偶然的。

  

崩溃转储文件在所有这些连接中的作用是什么,我可以用它来缩小问题的范围?

无。您只能从开发人员的知识中得出结论:不匹配的PDB和DLL的时差是多少,以及您在哪些文件中进行了多少更改。使用版本控制差异来找出它。

如果您对源代码进行了更改

这种匹配可能会出错,因为

  • 你同时重命名了这个方法。然后方法名称不匹配
  • 您已插入行,例如评论。然后行号不匹配
  • 您已重命名源文件。然后源文件不匹配。
  • 你添加了一个课程。这可能会改变编译器生成相关方法的地址,因为它具有例如之前插入了新课程。

如果您尚未对源代码进行更改

这种匹配仍然可能出错,因为

  • 您的编译器环境已更改,例如由于编译器中的更新或修补程序,它现在生成不同的汇编指令。
  • 您使用不同的编译器设置进行编译(希望您的编译器设置与源代码一起存储在版本控制系统中,因此您不会遇到此问题)
  • 编译器不需要在另一次运行中以完全相同的方式编译。虽然没有特别的理由以不同的方式编译它,但现在编译器可以并行编译(多线程)。由于线程调度,某些类可能以不同的顺序编译,这可能会也可能不会导致不同的DLL + PDB(取决于编译器或链接器的实现)。