In my experience, symbol servers are useful for both managed and unmanaged debugging, as they provide much needed details. Others have already examined why this is important for native code, so I will stick with managed code.
I am doing the honest part of debugging managed code using WinDbg + Sos, and I need to paste it into the source part regularly. Remember that for an OS, a managed application is no different from an unmanaged application. In the end, the managed application will call the Win32 DLL. To check those, you need the correct characters.
eg. if you need to know the details of a particular managed call, you really need to look at your own code. For example, you can see Monitor.Enter in a managed stack. You cannot tell, looking at the call yourself, if the call was just issued or if the thread is really waiting (*). By dropping your own call stack, you can see if a WaitForMultipleObjects call has been issued.
(*) The status flags of the !threads command will help you here, but if you need details, dumping your own stack is still very useful.
source share