2008-05-01

If you need a Windows debugger, there's plenty of choice

One thing Windows programmers cannot complain about is a lack of debugging support. Microsoft produces its own debuggers, for both managed and unmanaged scenarios, and they offer just about everything you could ask for (including scriptability and extension hooks for when they don't immediately offer what you want). Here's an overview of all the debuggers available, with a feature matrix, which is intended to be complete.

Name Console/GUI Unmanaged code Managed code Kernel debugging Remote debugging
cdb Console Yes Limited (sos.dll) No Yes
cordbg Console No Yes No Yes
dbgclr GUI Limited Yes No No
kd Console Yes Limited (sos.dll) Yes Yes
mdbg Console No Yes No No
ntsd Console Yes Limited (sos.dll) No Yes
Visual Studio GUI Yes Yes No Yes
windbg GUI Yes Limited (sos.dll) Yes Yes

Why are there so many debuggers, and which one should you pick? There's a lot of overlap in features.

Let's start with the native debuggers: cdb, kd, ntsd and windbg. These are all part of the Debugging Tools for Windows package.

The native debuggers excel at debugging unmanaged code, but debugging managed code is a little clumsier as support is provided only through extensions (more on that later). The most feature-complete of them is windbg, which has a GUI as well as support for both kernel- and user-mode debugging. kd offers only kernel-mode debugging (but you can run one of the user-mode debuggers on top of it) while cdb and ntsd offer only user-mode debugging. Actually, cdb and ntsd are essentially the same debugger, the only difference being that cdb will use the same console window it was started in (if any) while ntsd will always open a new console window. Aside from the split between kernel-mode and user-mode, which native debugger you use is mostly a matter of preference.

All native debuggers have extensive support for remoting, from having them act as dumb clients to the remote debugger to having the debugger on your end do symbol lookup as well (which can come in very handy if you cannot install or download symbols on the remote machine) and even the ability to debug processes on multiple machines simultaneously (to diagnose network protocol problems, for example).

The managed debuggers are a more varied bunch. The most important one (and for many developers the only one they know) is Visual Studio, which has its own integrated debugger. This debugger is capable of debugging both managed and unmanaged code and has a very complete GUI for both, including runtime expression evaluation of both managed and unmanaged expressions. It has some support for extensions DLLs, the same kind used by the native debuggers to provide enhanced debugging commands. Traditionally, remote debugging with Visual Studio has been rather error-prone and difficult to set up, but VS 2005 and 2008 have improved on matters by making it as simple as running a program from a remote share (at least for machines in the local network). VS has no support for kernel debugging.

dbgclr is an odd little duck that's only installed with the .NET 2.0 SDK, and nothing else (not even a full install of Visual Studio itself). Basically, dbgclr is a slimmed-down extract of the Visual Studio 2005 debugger — it's only the debugger and nothing else. Moreover, it's only the part that can debug (pure) managed code — mixed-mode debugging is not supported. Remote debugging isn't supported either. There's nothing dbgclr can't do that one of the other debuggers can't do better, but it beats Visual Studio in that the SDK install is at least marginally smaller (and does not require a license), so if you absolutely must have a managed debugger with a GUI but can't afford to install VS you could consider using dbgclr.

cordbg is also included with the Framework SDK and with the Windows SDK (or Platform SDK). It started out (in .NET 1.0) as a demonstration and bare-bones implementation of the CLR debugging interfaces, but it has basically evolved to being a skin for mdbg (coming up next). If you're not already used to how cordbg works, there's not much point in starting with it, since additional effort will mostly go into mdbg. Like mdbg, cordbg is a console-mode application.

mdbg is the main managed debugger after Visual Studio. It, too, is installed with both the Framework SDK and the Windows SDK. It's a console-mode debugger with a command syntax that is unfortunately completely different from that of the native debuggers, so knowing those won't help you get started with mdbg. mdbg cannot debug unmanaged applications, though it has support for disassembling unmanaged code (mostly to diagnose problems with JIT compilation). However, debugging managed code is much more comfortable than doing it with the extensions of the native debuggers. It has no support for remote debugging.

Mike Stall wrote up an excellent summary on the relative positions of the managed debuggers. That post is two and a half years old at the time of writing this, but it's still accurate in the sense that nothing much has changed. In particular, when he mentions that they'd like to stop shipping cordbg and even drop mdbg once the native debuggers get integrated support for unmanaged code, keep in mind that both cordbg and mdbg are still updated, and the native debuggers still have to make do with extensions.

I mentioned earlier that the native debuggers have some support for managed debugging through extensions. The extension in question is SOS.dll (short for "Son of Strike" — Jason Zander explains the name in his post on using SOS). By loading SOS, a whole host of commands for managed debugging become available which range from useful to indispensable. Because the default native commands don't know anything about managed code, their output is not always useful. For example, the k command decodes a call stack, but cannot handle managed frames; u will unassemble code but cannot resolve calls to JIT-compiled code to symbols. SOS offers replacements in the form of !CLRStack and !u, respectively. A full list of commands is available in the MSDN.

With all these tools at your disposal, which debugger(s) should you use? I prefer to think of it as order of preference:

  • Use Visual Studio if you can. It's by far the easiest to use and offers a wide range of features. For debugging managed code, it's unsurpassed in ease of use.
  • For advanced scenarios, like debugging mixtures of managed and unmanaged code (like interop scenarios), network protocol debugging and tracking down handle leaks and heap corruption, the native debuggers with SOS.dll are the most powerful. Visual Studio will quickly become frustrating to use in these scenarios.
  • For kernel debugging, you'll use windbg and kd and like it.

This is by no means the full story on Windows debugging. I've left out things like Managed Debugging Assistants (MDAs), extending the managed debugging framework, Visual Studio's support for native debugger extensions, third-party debuggers, and profiling (which is not unrelated to debugging). For more information, check out one of the dedicated blogs in the links section.

Links

Here's a list of the most important links in the article, plus some useful ones that weren't mentioned.

No comments: