The ICorDebug API (the API for debugging managed apps) is about 70 total interfaces. Here is how I’d group the interfaces together, along with my random comments about how various interfaces fit into the big picture.
A quick comment about interface versioning:
1. ICorDebug is a COM-classic unmanaged interface. Most of the interfaces are derived from IUnknown because we wanted to avoid the diamond-inheritance problem when we needed to add version 2 interfaces. I’ve left the “Derives From” column blank if an interface derives from IUnknown.
2. Version 2 interfaces have the previous interface’s name appended with a version number. (eg, “IFoo2”)
I’d roughly partition it into the following groups:
Top-level: ICorDebug + ICorDebug2 are the top-level interfaces which effectively serve as a collection of ICorDebugProcess objects.
|ICorDebug||Top level object which hands out all other objects. You can create an instance of ICorDebug with the CreateDebuggingInterfaceFromVersion function.|
|ICorDebug2||Container for interface versioning data|
Callbacks: Managed debug events are dispatched via methods on a callback object implemented by the debugger:
|ICorDebugManagedCallback||Callback interface to dispatch managed debug events to debugger.|
|ICorDebugManagedCallback2||new V2 callbacks|
|ICorDebugUnmanagedCallback||dispatch native DEBUG_EVENT for interop-debugging|
|ICorDebugMDA||Packages parameters for the Managed Debug Assistant (MDA) callback. This was done because MDAs have some potentially large string parameters that we wanted to allow lazy retrieval of.|
Process: This set of interfaces represents running code and includes the APIs related to eventing.
|ICorDebugController||It has Stop/Go methods related to whether threads are stopped or running such as Stop(), Continue(), IsRunning(), HasQueuedCallbacks(), etc.
This is the base interface for ICorDebugProcess and ICorDebugAppDomain.
|ICorDebugProcess||ICorDebugController||Represents a live process. The Stop/Go methods operate on the entire process, just as their counterparts would in native debugging.|
|IcorDebugAppDomain||ICorDebugController||Represents an appdomain within a process. AppDomain derives from Controller because we wanted the API to support partial-process-debugging on a per-AppDomain basis.|
Code / Type Inspection: Could mostly operate on a static PE image, although there are a few convenience methods for live data.
|ICorDebugAssembly||Represents an assembly. While assemblies are very important for deployment and versioning issues, they are a largely uninteresting abstraction to the debugger. Practically for a debugger, an Assembly is a module container.|
|ICorDebugModule||Represents a module. Modules are very significant to the debugger because that corresponds to raw files. A module is 1:1 with a metadata importer, and associated with a PDB file.|
|ICorDebugFunction||Represents a method as defined in the IL. ICDFunction is 1:1 with a MethodDef. So there is 1 ICDFunction for List<T>::Add(T item). Edit-and-Continue introduces new IL, and thus new ICDFunction instances.|
|ICorDebugCode||Represents either IL or native code bytes for a function. This is 1:1 with the raw code. So if “Add(T item)” instantiated twice for “Add(String item)” and “Add(int item)”, each would get their own ICDCode instance (unless the instances shared the same code bytes).|
|ICorDebugCode2||Support non-contiguous code bytes. This lets the JIT optimize how basic blocks get mapped to hot pages.|
|ICorDebugClass||Represents a type (either Reference-Type or Value-Type) as defined in the IL. ICDClass is 1:1 with a TypeDef, and so it does not handle generics. An ICDClass may represent “List<T>”|
|ICorDebugType||Added in V2 to handle generics. Represents the fully instantiated type. An ICDType may represent “List<int>”.|
Execution Control: Execution is the ability to “inspect” a thread’s execution. Practically, this means things like placing breakpoints (F9) and doing stepping (F11 step-in, F10 step-over, S+F11 step-out). ICorDebug’s Execution control only operates within managed code.
|ICorDebugBreakpoint||Abstract base interface for breakpoints|
|ICorDebugFunctionBreakpoint||ICorDebugBreakpoint||Breakpoint somewhere in managed code.|
|ICorDebugStepper||Interface for step operations within managed code. More on stepping here|
|ICorDebugStepper2||Added support for Just-My-Code (JMC)|
|ICorDebugEval||Support for func-eval. From an API perspective, func-eval is definitely execution control: it injects a call into the app, lets the app run, and then waits for an aysynchronous complete event. From a end-user perspective, func-eval is generally used as an inspection tool (eval property getters and ToString)|
|ICorDebugEval2||Just like ICorDebugEval but using ICorDebugType to support generics.|
Threads + Callstacks: Callstacks are the backbone of the debugger’s inspection functionality. The following interfaces are related to taking a callstack. ICorDebug only exposes debugging managed code, and thus the stacks traces are managed-only.
|ICorDebugThread||Represents a managed thread, which is a thread that has entered managed code at some point. This includes threads are currently in native code and may not even have any managed frames on their stack. More trivia here.|
|ICorDebugChain||Collection of frames on the callstack. I personally think this is a stupid abstraction and we should never had had this interface. It’s just one more hassle to get a stack trace.
Each range of unmanaged frames are also grouped together under a single ICDChain instance (with the Managed property set to false). A debugger can manually walk native frames from these chains and then stitch them back in with the managed frames to get a mixed-mode callstack.
|ICorDebugFrame||Abstract base interface for a frame on the callstack|
|ICorDebugILFrame||ICorDebugFrame||Exposes the IL properties of a frame (such as the IL offset, IL locals).|
|ICorDebugNativeFrame||ICorDebugFrame||Exposes the native properties of a managed frame (such as the native offset). This does not expose any information about unmanaged frames.|
|ICorDebugInternalFrame||ICorDebugFrame||Added in whidbey to let ICD mark “interesting” spots in the stack such as stubs that may catch or throw exceptions. These are a cleaner way to provide ICDChain functionality.|
|ICorDebugRegisterSet||Provide an abstract view of a CONTEXT. This allows representing contexts that don’t have all registers valid, such as the context on a non-leaf stack frame.|
|ICorDebugRegisterSet2||Add 64-bit support to ICorDebugRegisterSet|
Object Inspection: Object inspection is the part of the API that lets you see the values of the variables throughout the debuggee. For each interface, I list the “MVP” method that I think must succinctly conveys the purpose of that interface.
|Interface||Derives from||Comments||MVP method|
|ICorDebugValue||Base class for value inspection|
|ICorDebugValue2||Addition for generics to get an ICorDebugType||GetExactType|
|ICorDebugGenericValue||ICorDebugValue||Represents primitive blittable values like int, double, etc.||GetValue|
|ICorDebugObjectValue||ICorDebugValue||Represents an actual object with fields (reference or value type). The GetSize() property of this will be the size of the actual object.||GetFieldValue|
|ICorDebugReferenceValue||ICorDebugValue||Represents a reference value. The GetSize() property of this will be sizeof(void*).||DereferenceValue|
|ICorDebugHandleValue||ICorDebugReferenceValue||Lets the debugger create a handle to provide object identity.||DereferenceValue|
|ICorDebugBoxValue||ICorDebugHeapValue||Represents a boxed value||GetObject|
|ICorDebugStringValue||ICorDebugHeapValue||Represents a System.String.||GetString|
|ICorDebugArrayValue||ICorDebugHeapValue||Represents an array.||GetElementAtPosition|
Enumerators: All enumerators in ICorDebug derive from the ICorDebugEnum class and have the same usage semantics. I put the enumerators off into their own group because conceptually, we don’t users to focus on them specifically. For example, in a managed wrappers, all the enumerators could be exposed as IEnumerable<T>, and thus wouldn’t have their own dedicated types. Not all of these enumerators are implemented.
Deprecated / Never implemented: These are listed for completeness sake. Since they’re not used, I’ll refrain from commenting about them.
Note that this is not intended to be any form of official documentation. See MSDN for official docs and specs.This is just my random commentary.
I may come back and update this in the future.