Click here to Skip to main content
Click here to Skip to main content

Tagged as

Writing a .NET debugger (part 2) – Handling events and creating wrappers

, 28 Oct 2010
Rate this:
Please Sign up or sign in to vote.
Writing a .NET debugger (part 2) – Handling events and creating wrappers

In this part, I will describe which events the debugger has to deal with and how it should respond to them. Additionally, we will create few COM wrappers for ICorDebug* interfaces. Let’s first examine the ICorDebugManagedCallback interface (imported from COM object – more in part 1). You may notice that each event handler has its own set of parameters, but the first parameter is always of type either ICorDebugAppDomain or ICorDebugProcess. Both ICorDebugAppDomain and ICorDebugProcess implement ICorDebugController which allows you to control the debuggee.

In part 1, we ended with an application that could start a new process or attach to the running one and then stop it. We will now find a way to make the process running and log all events coming from it. Let’s introduce a simple HandleEvent method which will be called from all other event handlers (except ICorDebugManagedCallback.ExitProcess):

void HandleEvent(ICorDebugController controller)
{
    Console.WriteLine("event received");
    controller.Continue(0);
}

All events handlers bodies (except ICorDebugManagedCallback.ExitProcess) will now look as follows:

{
    HandleEvent(pAppDomain); // or HandleEvent(pProcess) if first parameter is pProcess
}

If we now execute our application, it will print few “event received” messages and then stop. Under the debugger, we will see that the debugging API throws a COM exception:

System.Runtime.InteropServices.COMException crossed a native/managed boundary
  Message=Unrecoverable API error. (Exception from HRESULT: 0x80131300)
  Source=mindbg
  ErrorCode=-2146233600
  StackTrace:
       at MinDbg.NativeApi.ICorDebugController.Continue(Int32 fIsOutOfBand)
       at ...

It took me some time to figure out why this error occurred. It seems that in order to be able to receive all managed events, the debugger must be attached to the debuggee appdomains. So I needed to modify the ICorDebugManagedCallback.CreateAppDomain handler by adding one new instruction:

void ICorDebugManagedCallback.CreateAppDomain
	(ICorDebugProcess pProcess, ICorDebugAppDomain pAppDomain)
{
    pAppDomain.Attach();
    HandleEvent(pProcess);
}

Finally, our debugged process executes normally without any interruption from the debugger side.

Let’s now focus on the second topic of the post: ICorDebug COM wrappers. As COM objects are not very comfortable in use and certainly we don’t want to pass them outside the bounds of the assembly, we need to create a way to represent them in our application. For each used ICorDebugName interface we will create a CorName class that will implement methods and properties which will give access to the inner COM object API. Additionally these wrappers should be comparable so we could later check whether the object returned from a callback function is the same as the one that we already have. This is even better explained in the mdbg source code – look at the comment for the WrapperBase class. Our WrapperBase class would be actually almost the same as the one in mdbg sources:

/// <span class="code-SummaryComment"><summary>
</span>/// A base class for all COM wrappers.
/// <span class="code-SummaryComment"></summary>
</span>public abstract class WrapperBase : MarshalByRefObject
{
    protected WrapperBase(Object value)
    {
        Debug.Assert(value != null);
        coobject = value;
    }

    /// <span class="code-SummaryComment"><summary cref="System.Object.Equals">
</span>    /// <span class="code-SummaryComment"></summary>
</span>    public override bool Equals(Object value)
    {
        if (!(value is WrapperBase))
            return false;
        return ((value as WrapperBase).coobject == this.coobject);
    }

    /// <span class="code-SummaryComment"><summary cref="System.Object.GetHashCode">
</span>    /// <span class="code-SummaryComment"></summary>
</span>    public override int GetHashCode()
    {
        return coobject.GetHashCode();
    }

    /// <span class="code-SummaryComment"><summary>
</span>    /// Override also equality operator so we compare
    /// COM objects inside instead of wrapper references.
    /// <span class="code-SummaryComment"></summary>
</span>    /// <span class="code-SummaryComment"><param name="operand">first operand</param>
</span>    /// <span class="code-SummaryComment"><param name="operand2">second operand</param>
</span>    /// <span class="code-SummaryComment"><returns>true if inner COM objects are the same, false otherwise</returns>
</span>    public static bool operator ==(WrapperBase operand, WrapperBase operand2)
    {
        if (Object.ReferenceEquals(operand, operand2))
            return true;

        if (Object.ReferenceEquals(operand, null)) // this means that operand==null && 
						// operand2 is not null
            return false;

        return operand.Equals(operand2);
    }

    /// <span class="code-SummaryComment"><summary>
</span>    /// Override also inequality operator so we compare
    /// COM objects inside instead of wrapper references.
    /// <span class="code-SummaryComment"></summary>
</span>    /// <span class="code-SummaryComment"><param name="operand">first operand</param>
</span>    /// <span class="code-SummaryComment"><param name="operand2">second operand</param>
</span>    /// <span class="code-SummaryComment"><returns>true if inner COM objects are different, true otherwise</returns>
</span>    public static bool operator !=(WrapperBase operand, WrapperBase operand2)
    {
        return !(operand == operand2);
    }

    private Object coobject;
}

That’s all for today. The source code for the second part is available here. You may also connect to the TFS repository and download the 54704-th revision of the code.


Filed under: CodeProject, Debugging

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sebastian Solnica
Software Developer (Senior)
Poland Poland
Interested in tracing, debugging and performance tuning of the .NET applications (especially ASP.NET).
 
If you find this article interesting, maybe you would like to pay me a visit: http://lowleveldesign.wordpress.com? Smile | :)

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 28 Oct 2010
Article Copyright 2010 by Sebastian Solnica
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid