Managed vs. Native debugging APIs

FxCop has a great rule (UseManagedEquivalentsOfWin32Api) to tell you about managed APIs that exist instead of trying to pinvoke out. 

I'm writing a native debugger in managed code (more on this later), and FxCop was telling me to use the managed debugging APIs instead of pinvoke out to the native ones. This came up in the fxcop forums. This raises an interesting point about the difference between some of the managed vs. native debugging APIs. Managed and Native debugging are (as of .NET 2.0) different services and so have different APIs with subtle distinctions.

Now, odds are that if you're running managed code (which you must be to do a pinvoke in the first place), then you care about managed-debugging and actually want to be calling the managed versions. In that case, Debugger.IsAttached(), Debugger.Break(), Debugger.Log() are really the one you care about. However, these APIs are still significantly different from their native counterparts. So if you are writing a native-debugger in managed code and really intend to pinvoke out to the native debugging APIs, you can't just replace them with the managed counterparts.
 

DebugActiveProcess != System.Diagnostics.Debugger.Launch
These ones are totally different.
System.Diagnostics.Debugger.Launch will (i) launch a (ii) managed debugger (using registry settings to find it), with the intent of attaching it to the (iii) current process.
kernel32!DebugActiveProcess will tell the current process to start (i) attach as a (ii) native debugger to the (iii) specified process (not the current process).

DebugBreak != System.Diagnostics.Debugger.Break
DebugBreak injects a (i) native breakpoint exception (eg, int3 on x86). If no native debugger is attached, it will use (ii) normal SEH processing, which may trigger an unhandled native exception and native jit-attach.
Debugger.Break injects a (ii) managed stop (UserBreak) and if no managed debugger is attached, it will (ii) trigger a jit-attach for a managed debugger.

IsDebuggerPresent != System.Diagnostics.Debugger.IsAttached
See here for more details. In short, kernel32!IsDebuggerPresent tells you if a (i) native debugger is attached (which includes interop-debugging), whereas Debugger.IsAttached tells you if a (i) managed debugger is attached. As of .Net 2.0, this is a significant distinction. This may change in the future (eg, if we built managed debugging on top of native debugging).

So for your standard C# debugging experience, IsDebuggerPresent() will return false while Debugger.IsAttached() will return true.

However, both of these APIs are evil because debuggers aren't supposed to change behavior, so please don't call them unless you really know what you're doing.

OutputDebugString =? System.Diagnostics.Debugger.Log
These are the closest in relationship. See here for more details. If you're writing managed code, you probably want to call Debugger.Log() instead of pinvoke out to OutputDebugString.
 

 

Summary:
1. The manage and native debugging APIs are functionally very different.
2. However, if you're writing in managed code, you probably intend to use the managed methods on Debugger (especially Debugger.Log and Debugger.Break)
3. If you are indeed writing a native debugger in managed code, then the differences between the method sets are important.