Retail code debugging is one of those necessary evils. It's difficult, but the only way to completely avoid it is to not have retail code, which unfortunately usually requires you to avoid having any customers. Anyway, I figured I would give a brief tour of what you can trust and what you can't trust while you are retail debugging.
First the most important advise I can ever give – ALWAYS generate pdbs, and always keep the PDBs for any binary that you ship. If you work for a software company that doesn't do this, let me know so that I can avoid their products :).
Next, for the 1.0 and 1.1 versions of the CLR, retail debugging is pretty much out. Unless you start the application under the debugger or do some other funky thing, the Just-In-Time compiler will not generate the data on how it mapped IL instructions to native instructions. If you happen to have a reliable repro that doesn't go away when launched under the debugger, then you can debug your code that way. However, if you have a reliable repro, why mess with retail debugging? Anyway, because of this I am only going to talk about native debugging from here on out.
What you can trust:
NOTE: Other then the return address, everything else is going to depend on compiler optimizations, and calling conventions (for calling conventions, see Raymond's blog). However, this is a good rule of thumb.
So what can't you trust? Anything accessed from a local or parameter. Unfortunately, this is almost everything (example: member variables are accessed via a parameter: 'this').
So, what do you do?
As long as you have symbols for every frame on the callstack, the callstack window should produce accurate results. Caveats:
Stepping and breakpoints should both work reliably, but this doesn't mean that they will work like you expect.
The disassembly window is generally your friend when you are stepping through code.