Working on managed wrappers for Native Debugging API

FWIW, I've been working on some managed wrappers for the native debugging API (kernel32!WaitForDebugEvent,etc)

My goals are:

  1. Make it extremely easy to use the native debugging API. 
  2. Maintain fidelity to the native debug API. I didn’t want a super thick wrapper, but I was willing to track some extra state to make things easy.
  3. Smooth over various warts of native-debugging. Eg, dealing with the loader breakpoint, knowing what you’re supposed to close on ContinueDebugEvent, continuing OutputDebugString events.  It also gives me a chance to embed key API trivia in xml comments.
  4. Making it cross-plat, particularly working on both 32 and 64 bit. Importing DEBUG_EVENT for both 32 and 64 bit was annoying. If you put the abstractions at the right place, the debugging API is pretty cross-platform from the client end, although some implementations (eg, setting a single-step flag) are of course platform specific.
  5. Provide useful utility functions, like getting the module name from a LoadDll event or message string from a OutputDebugString event.

In my test app, the debugger's main loop could be something like:
 

        NativePipeline dbg = new NativePipeline();
dbg.CreateProcessDebug(args[0], null);

        while (true)
{
            NativeEvent e = dbg.WaitForDebugEventInfinite();
e.Process.HandleIfLoaderBreakpoint(e);

            Console.WriteLine("Event:{0}", e);
dbg.ContinueEvent(e);

            if (e is ExitProcessDebugEvent)
{
                break;
}
}

And that prints something like:

Event:Event Type:tid=2540, code=CREATE_PROCESS_DEBUG_EVENT
Event:DLL Load:Address 0x7c900000, ntdll.dll
Event:DLL Load:Address 0x79000000, C:\WINDOWS\system32\mscoree.dll
Event:DLL Load:Address 0x7c800000, C:\WINDOWS\system32\KERNEL32.dll
Event:Exception Event:Tid=2540, 0x80000003, first chance, address=0x7c901230
Event:DLL Load:Address 0x77dd0000, C:\WINDOWS\system32\ADVAPI32.dll
Event:DLL Load:Address 0x77e70000, C:\WINDOWS\system32\RPCRT4.dll
Event:DLL Load:Address 0x77f60000, C:\WINDOWS\system32\SHLWAPI.dll
Event:DLL Load:Address 0x77f10000, C:\WINDOWS\system32\GDI32.dll
Event:DLL Load:Address 0x77d40000, C:\WINDOWS\system32\USER32.dll
Event:DLL Load:Address 0x77c10000, C:\WINDOWS\system32\msvcrt.dll
Event:DLL Load:Address 0x79e70000, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Event:DLL Load:Address 0x78130000, C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.42_x-ww_0de06acd\MSVCR80.dll
Event:DLL Load:Address 0x7c9c0000, C:\WINDOWS\system32\shell32.dll
Event:DLL Load:Address 0x773d0000, C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll
Event:DLL Load:Address 0x5d090000, C:\WINDOWS\system32\comctl32.dll
Event:DLL Load:Address 0x60340000, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\culture.dll
Event:Event Type:tid=4072, code=CREATE_THREAD_DEBUG_EVENT
Event:Event Type:tid=4120, code=CREATE_THREAD_DEBUG_EVENT
Event:DLL unload:Address 0x60340000,C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\culture.dll
Event:DLL Load:Address 0x790c0000, C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\634bc4cfaf50134f9bc49aedecf3b262\mscorlib.ni.dll
Event:DLL Load:Address 0x774e0000, C:\WINDOWS\system32\ole32.dll
Event:DLL Load:Address 0x79060000, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll
Event:OutputDebugString:tid=2540, message=cat
Event:OutputDebugString:tid=2540, message= :
Event:OutputDebugString:tid=2540, message=Hi!
Event:OutputDebugString:tid=2540, message=
Event:Event Type:tid=4120, code=EXIT_THREAD_DEBUG_EVENT
Event:Event Type:tid=4072, code=EXIT_THREAD_DEBUG_EVENT
Event:Event Type:tid=2540, code=EXIT_PROCESS_DEBUG_EVENT

 

There's still an open question about what I'll do about symbols. At the raw API level, everything's pretty much policy-free. But once you get symbols you get a whole head-ache of symbol paths, symbol loading policy, symbol servers, diagnosing symbol failures, which symbol API to use, how much of the symbol API to import, etc.

My plan is to roll these into the MDbg sample, and so interested parties will get the full source to them.

[Update:] Source is now available here.

Comments

  • Anonymous
    July 05, 2006
    This is great! Having something that works on 32 and 64 bit will make it particularly useful. I look forward to seeing the code. :)

    Thanks, Jamie.

  • Anonymous
    July 05, 2006
    Awesome! When do you expect to release them?

  • Anonymous
    July 06, 2006
    DebugLover - not sure yet. We can release the mdbg sample out-of-band of shipping the .NET product, so it could be arbitrarily soon.
    I'm going as quickly as I can :)
    do you have some immediate need; or are you just curious?

  • Anonymous
    July 06, 2006
    Sooner would be nicer as it allows me to move away from my current 100% non-managed way of doing things.

  • Anonymous
    July 06, 2006
    Super, Cross platform native debugger in managed code is great news.

    I'm working on a Debugger for Java(Sorry!! but they deserve a good debugger too) in C#. Basic architecture is similar to Mdbg(simply because its awesome)
    Debug API is almost (!) ready,
    I was wondering about using your managed wrappers to provide JNI(Java native interface) debugging(same as Interop debugging in .NET, Native dlls are loaded into JVM and can be called from Java class) functionality as well.

    Is it possible to release a pre-alpha version or something? I'm not being pushy here.

  • Anonymous
    July 09, 2006
    Very nice.  Are you trying to push PEBrowse Interactive out of business? - :o)

    Are you using managed C++ or C# for your wrappers?  I have found it to be trivial to use managed C++ in scenarios where there is a wealth of headers available.  And with a little more work one can create a DLL that will interface with both managed projects in the IDE and native only applications.

  • Anonymous
    July 09, 2006
    The wrappers are in C# - the marshalling in this case is actually pretty easy. MC++ can definitely be great for wrapping more complex things. I suggested using that for an debugger that wanted to wrap V1.1 IcorDebug. (MDbg only works on V2)

    In fact, you could even compile MC++ to pure IL and then decompile it (ildasm / reflector) to C#.

  • Anonymous
    July 11, 2006
    I'm writing some managed wrappers for the native-debugging API (I expect they'll eventually become part...

  • Anonymous
    November 22, 2006
    We've just updated the MDbg sample! This is a full source sample for building a managed debugger in C#.

  • Anonymous
    November 23, 2006
    Today we released the latest version of the managed debugger - MDbg. For the past few days, we've been

  • Anonymous
    February 27, 2007
    The comment has been removed