在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 kernel32.dll!_BaseProcessStart@4() + 0x23 bytes
调试器将显示警告Frames below may be incorrect and/or missing
。
(请注意,只有01和02行没有符号。第00行,我设置了一个断点,所有其他行都加载了符号。)
现在,我知道如何修复警告( - >获取pdb文件),我完全不知道为什么它会显示出来!我上面粘贴的堆栈完全没问题,只是我没有dynlib2.dll模块的pdb文件。
为什么调试器需要一个符号文件来确保堆栈是否正确?
答案 0 :(得分:4)
我认为这是因为并非所有功能都遵循“标准”堆栈布局。通常每个函数都以:
开头push ebp
mov ebp,esp
以
结束pop ebp
ret
通过这个,每个函数都会创建所谓的堆栈帧。 EBP
始终指向顶部堆栈帧的开头。在每个帧中,前两个值是指向前一个堆栈帧的指针,以及函数返回地址。
使用此信息可以轻松地重建堆栈。但是:
答案 1 :(得分:1)
I tried to understand this myself a while ago.
截至2013年,FPO未在MSFT中使用,并且通常不赞成。我确实遇到过内部使用的不同MS二进制技术,这可能会妨碍天真的EBP链遍历:Basic Block Tools。
如帖子中所述,PDB确实包含'StackFrameTypeEnum',而其他地方则暗示它们包含堆栈帧的'展开程序'。总而言之,它们仍然是必需的,而且为什么确切的血腥细节 - 没有记录。
答案 2 :(得分:0)
符号与相关的二进制代码分离,以减少发送二进制文件的大小。检查PDB文件有多大 - 特别是与匹配的二进制文件(EXE / DLL)相比。每次运送,安装和使用二进制文件时,您都不希望出现这种开销。这在加载时尤为重要。符号信息毕竟只用于调试,不是正确操作代码所必需的。如果您保留符合已发送二进制文件的符号,则仍可以在加载所有符号的情况下调试问题。