The Visual Studio .NET debugger supports debugging multiple types of code running in the same process. This is an important feature, and implementing it required huge changes in how the debugger works. Unfortunately, a bit too much of the implementation details of this seeped through to the user interface, which makes this feature somewhat confusing. In this post, I hope to add some clarity. If you think this is confusing, hopefully we will do a better job in Whidbey.

Program defined.

This brings me to a piece of vocabulary, ‘program’. As the Visual Studio .NET Debugger presents it, we give the word ‘program’ a special meaning. A program is a collection of code executing inside a process. A program is not the same as a process. Every process contains at least one program – the native Win32 code in the process. But it might also have other kinds of code. This could be Script, .NET code, T-SQL code, or code from some other interpreter. For instance, internet explorer usually has a script program, and a native program. As another example, managed applications have at least one managed program, and they have a native program. For managed code, we represented each app domain as a program.

Why does the user need to know about programs?

For some kinds of debugging, the answer is – you don’t. If you are managed debugging only an application that creates no extra app domains, there is only one program. Similarly, if you are native only debugging, you only have one program to deal with.

However, if you ever debug both the native and the managed code in a process at the same time, it helps to understand programs. Whenever the debugger is stopped, it has a current program. Here is the effect of the current program of various debugger windows:

Expression evaluation windows (watch, quick watch, immediate, memory, locals, autos, this, registers): Can only evaluate data inside the current program. So you can’t see your native global variables when your current program is .NET, and you can’t see your .NET statics when your current program is native.

Exceptions, Callstack, breakpoints: These windows are unaffected by the current program.

Threads: Only threads of the current program are shown.

Disassembly: You can go to disassembly from source for a program which is not the current program. However, the ‘Address’ edit box is sent only to the current program.

Modules: Normally the modules window only shows modules in the current program. However, if you right click on the module window, you can turn on the option to ‘Show modules for all programs’. If you do this, you will see that many modules will be listed multiple times. Example:

  InteropTest.exe 00400000-00408000 C:\Documents and Settings\Gregg\My Documents\Visual Studio Projects\InteropTest\bin\Debug\InteropTest.exe 1 1.00.1498.19481 [368] InteropTest.exe: Native 2/7/2004 10:49 AM No native symbols in symbol file.
  InteropTest.exe 00400000-00408000 C:\Documents and Settings\Gregg\My Documents\Visual Studio Projects\InteropTest\bin\Debug\InteropTest.exe 2 1.0.1498.19481 [368] InteropTest.exe 2/6/2004 8:32 PM Symbols loaded.

In this case, I was native and managed debugging a test application (InteropTest.exe), and this is the InteropTest.exe module. You can tell the difference between the native module, and the managed module from the program column. For this particular case, you could also tell the difference because the native program says ‘No native symbols in symbol file’.

Switching the current program

There are two ways to control the current program. First, you can double click a frame in the callstack window. The other way is to enable the debug location toolbar. The first listbox in the debug location toolbar allows you to switch the current program. For my test application, I get two programs:

[368] InteropTest.exe : Native
[368] InteropTest.exe

The top program represents the native (Win32) program. The bottom program is the managed (.NET) program. If my test applications contained additional app domains, I would see other programs in this drop down as well.