Harness that Attach instead of Launch

I’ve given sample code for MDbg-based harnesses that launch an app and then print all loaded modules or print exceptions that occur.  In both cases, the harness launches the app. One reader asked how to modify them to attach to an existing app. It’s actually very easy.
In either case, we need to get an MDbgProcess instance. In the launch case, we get it via CreateProcess (which ultimately calls ICorDebug::CreateProcess) with something like:
    MDbgProcess proc = debugger.CreateProcess(szProgramName, “”, DebugModeFlag.Default, null);

To attach to an existing process, we need to switch this over to calling ICorDebug::DebugActiveProcess() on a given pid. That could look like this:
    int pid =  (… get pid of interest …);
    MDbgProcess proc = debugger.Attach(pid);

I just tried out the change on the Load-Module harness and it worked on the first time.

Perhaps a related interesting question is how to figure out the pid to attach to given the name. See here for sample code to answer that question.

API differences between Launch and Attach:
Once you have the MDbgProcess or ICorDebugProcess, the rest of the API looks the same.  ICorDebug will actually fake up certain notifications (LoadModule, CreateThread, etc) by enumerating all modules, threads, etc that exist at the time of attach and then firing “fake” callbacks for them.   (The native debugging API does this too)
I have mixed feelings about this. On one hand, firing “fake” callbacks is lying, and lying causes grief in APIs. On the other hand, it sure can be convenient because it unifies both the Launch and Attach scenarios. After all, we only had to change a single line in the example to go from Launch to Attach.

Also, there is no managed “attach complete” callback. This is in contrast to the native API which does have a “loader breakpoint” (99.9% of the time, the first int 3). Thus there is not a good way in V2.0 to tell when you’ve stopped getting “fake” events and started getting “real” events again.

[Update: 11/19/05]  MDbg tries to help out here. Once you Go() after an Attach(), it will pump all the “fake” events and return a psuedo “AttachCompleteStopReason”. This is very useful if you want a harness that attaches and does inspection instead of sniffs for debug events.

Comments (7)

  1. I am with you on the "mixed feelings." Do the fake module load events follow load or initialization order? Do the fake create thread events follow the order the threads are created? From your last statement I understand that there is no way, native or managed, to distinguish a fake from the real notification. Is this correct?

  2. jmstall says:

    The order of the fake events are unspecified; although it’s possible people may observe certain patterns (such as appearing to correlate to load order at times).

    Likewise, in the current implementation, there is a pattern that could be used to find when the fake notifications end; but it is

    a) not specified

    b) highly implementation dependent.

    c) may change in the future.

  3. Alexey Medvedev says:

    Do ICorDebug call "fake" callbacks in Framework 1.0 and Framework 1.1?

  4. jmstall says:

    Alexey – Yes.

  5. Mira says:

    Your blog is very interesint

  6. I wrote a simple tool to take a snapshot of a running managed process and dump the output as an XML file….