views:

55

answers:

2

When debugging in Visual Studio, if symbols for a call stack are missing, for example:

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 

the debugger will display the warning Frames below may be incorrect and/or missing.

(Note that only lines 01 and 02 have no symbols. Line 00, where I set a breakpoint and all other lines have symbols loaded.)

Now, I know how to fix the warning (->get pdb file), what I do not quite get is why it is displayed after all! The stack I pasted above is fully OK, it's just that I do not have a pdb file for the dynlib2.dll module.

Why does the debugger need a symbols file to make sure the stack is correct?

A: 

Symbols are decoupled from the associated binary code to reduce the size of shipping binaries. Check how big your PDB files are - huge, especially compared to the matching binary file (EXE/DLL). You would not want that overhead every time the binary is shipped, installed and used. This is especially important at load time. The symbol information is only for debugging after all, not required for correct operation of your code. Provided you keep symbols that match your shipped binaries, you can still debug problems post mortem with all symbols loaded.

Steve Townsend
What exactly has this answer to do with the question? (Except roughly matching the same tags?)
Martin
My point is that you won't see full symbolic debugging info in the reconstructed callstack without the symbol file, because symbolic debugging info is not included in the binary file. My guess is that @valdo is implying that there is info in the symbol file that enables a full callstack to always be produced - I believe that is not the case, but would be happy to learn I am wrong.
Steve Townsend
+3  A: 

I think this is because not all the functions follow the "standard" stack layout. Usually every function starts with:

push        ebp  
mov         ebp,esp 

and ends with

pop         ebp  
ret

By this every function creates its so-called stack frame. EBP always points to the beginning of the top stack frame. In every frame the first two values are the pointer to the previous stack frame, and the function return address.

Using this information one can easily reconstruct the stack. However:

  1. This stack information won't include function names and parameters info.
  2. Not all the functions obey this stack frame layout. If some optimizations are enabled (/Oy, omit stack frame pointers, for instance) - the stack layout is different.
valdo