Debugging Optimized Code in Visual Studio 11
Executive summary: When using the Windows debugger engine to debug optimized C++ code compiled with Visual Studio 11 you can step into inline functions and see local variables that are stored in CPU registers.
The current (Visual Studio 2010 compiler) state of affairs is that compiler optimizations are way smarter than the debugger engine, which lacks the information necessary to map a fully optimized binary back to the source code in a reliable manner. This is why C++ developers don’t like debugging optimized code: as if the compiler-introduced reorderings which take you from one line to a completely unrelated line at a whim aren’t enough, you often don’t see all local variables because they are stored in CPU registers at runtime, and you can’t step into or set breakpoints in functions that have been inlined.
The Visual Studio 11 C++ compiler helps by emitting additional debug information in the PDB. This information allows the debugger to map more accurately the optimized assembly stream back to the source. Currently, to get this to work, you need the Visual Studio 11 C++ compiler to build your code and you need to use the most recent Debugging Tools for Windows build – it contains the Windows debugger you must then use to work with this information*. Fortunately, you can use the Windows debugger engine to debug C++ code without leaving Visual Studio 11 – which means it ain’t all that bad.
The magic ensues when you add the /d2Zi+ undocumented compiler flag to your C++ compiler settings. (Obviously, this is something that will change before the release.) When you launch your program with WinDbg, or use the Windows debugger engine in Visual Studio to debug your code, you will see local variables and will be able to step into inline functions:
Finally, this also means that the debugger will be able to show inline functions on a call stack. For example, if you encounter an exception in an inline function and store a crash dump of the problem, you’ll have the debugger point at the inline function as the source of the crash. In WinDbg, a call stack would look similar to the following, complete with line numbers:
(Inline) -------- VanillaC__ConsoleApp!AddTwoNumbers+0x9 [d:\...\vanillac++consoleapp.cpp @ 9]
0035fae4 00901267 VanillaC__ConsoleApp!wmain+0x39 [d:\...\vanillac++consoleapp.cpp @ 25]
0035fb24 75f7339a VanillaC__ConsoleApp!__tmainCRTStartup+0xfd
0035fb30 77049ed2 kernel32!BaseThreadInitThunk+0xe
0035fb70 77049ea5 ntdll!__RtlUserThreadStart+0x70
0035fb88 00000000 ntdll!_RtlUserThreadStart+0x1b
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)