2010-09-15 43 views
2

当在Visual Studio调试,如果调用堆栈符号丢失,例如:为什么调试器需要符号来重建堆栈?

00 > HelloWorld.exe!my_function(int y=42) Line 291 
01 dynlib2.dll!10011435() 
    [Frames below may be incorrect and/or missing, no symbols loaded for dynlib2.dll] 
02 dynlib2.dll!10011497() 
03 HelloWorld.exe!wmain(int __formal=1, int __formal=1) Line 297 + 0xd bytes 
04 HelloWorld.exe!__tmainCRTStartup() Line 594 + 0x19 bytes 
05 HelloWorld.exe!wmainCRTStartup() Line 414 
06 [email protected]() + 0x23 bytes 

调试器将显示警告Frames below may be incorrect and/or missing

(请注意,只有线01和02无符号00号线,在这里我设置一个断点和所有其他线路已加载的符号。)

现在,我知道如何解决警告( - >获得pdb文件),我不明白的是为什么它显示出来!上面粘贴的堆栈完全正常,只是我没有用于dynlib2.dll模块的pdb文件。

为什么调试器需要一个符号文件来确保堆栈是正确的?

回答

4

我认为这是因为并非所有功能都遵循“标准”堆栈布局。通常每个函数开头:

push  ebp 
mov   ebp,esp 

pop   ebp 
ret 

通过此功能,每一个创造它所谓的堆栈帧结束。 EBP总是指向顶层堆栈帧的开始。在每个帧中,前两个值是指向前一个堆栈帧的指针,以及函数返回地址。

使用此信息可以轻松重建堆栈。但是:

  1. 此堆栈信息将不包括函数名称和参数信息。
  2. 并非所有的函数都服从这个堆栈框架布局。如果启用了某些优化(例如,/ Oy,省略堆栈帧指针) - 堆栈布局不同。
0

符号与关联的二进制代码分离以减少运输二进制文件的大小。检查你的PDB文件有多大 - 特别是与匹配的二进制文件(EXE/DLL)相比。每当二进制文件发货,安装和使用时,您都不会希望发生这种开销。这在加载时尤其重要。符号信息仅用于调试,而不是正确操作代码所必需的。如果您保留符合您运输的二进制文件的符号,您仍然可以使用加载的所有符号调试死后问题。

+0

这个问题的答案到底是什么? (除了大致匹配相同的标签吗?) – 2010-09-15 14:10:24

+0

我的观点是,在没有符号文件的情况下,重构的callstack中不会看到完整的符号调试信息,因为符号调试信息不​​包含在二进制文件中。我的猜测是@valdo暗示符号文件中有信息能够完整地生成一个完整的调用堆栈 - 我认为情况并非如此,但很高兴知道我错了。 – 2010-09-15 14:27:04

1

I tried to understand this myself a while ago.

作为2013,FPO不内MSFT使用并且在通常皱眉。我遇到了内部使用的不同MS二进制技术,可能会妨碍幼稚的EBP链遍历:Basic Block Tools

正如后文中指出的那样,PDB确实包含'StackFrameTypeEnum',并且在其他地方暗示它们包含栈帧的'unwind program'。因此,总而言之,它们仍然是需要的,而为什么 - 这些细节没有记录。