The SDbgCore static library is the foundation of SDbgExt2. It contains the definition of IXCLRDataProcess3 (I think it’s the 3rd revision, I just made the name up), as well as the core classes and interfaces IClrProcess and ISDbgExt. It also contains many helper interfaces such as IClrObject(Array), and lots of callback interfaces. We’ll go through these one by one.
This is the interface that makes everything work. In the pervious version (.NET 4.0), almost all functions were executed via a single Request(…) method on the interface. In .NET 4.5, these requests were split into strongly typed functions.
I started by reverse engineering the VTable via the embedded symbols in mscordacwks.dll. The interface is implemented by ClrDataAccess, and is the 3rd interface in the VTable (hence IXCLRDataProcess3). Next, I began reverse engineering the parameters. This is obviously more difficult, but you can get an idea of the parameters in two ways.
First, since most functions are similar to their request counterparts in .NET 4, you can get an idea of the parameters via the request object. Second, by inspecting the call sites in SOS, we can get an idea of the parameters being passed in. It turns out that a large chunk of functions follow a few very similar signatures, so figuring out the parameter isn’t actually that tough. Also as a side note, the x86 calling convention (stdcall) here makes it a lot easier to reverse engineer than x64, so I did most of my reversing on the x86 version.
For the output structures, again I leveraged .NET 4.0’s structures. Obviously there were some changes / additions / removals, but again by looking at the call site in SOS, it’s not too hard to figure out which fields do what. Some of these structures are obviously incomplete, but there’s enough there to support the functionality I need.
The result of this is IXCLRDataProcess3.idl, which MIDL compiles to a C++ interface and type library.
ClrProcess is the lowest level new interface in SDbgExt2. It contains various utility methods, field accessors, heap enumeration, sort-of-reflection, and thread inspection. I tried to keep this interface as low-level as possible, which providing reusable methods for what would be used by the higher level methods.
For example, accessing a static field (see ClrProcess::GetStaticFieldValue) via IXCLRDataProcess3 is a fairly complicated process. This is the simplified algorithm:
- You need to find the actually field address (the FieldDesc)
- This can be done by scanning the method table recursively, and using IMetaDataImport to resolve a token to a name.
- Given a FieldDesc and app domain, figure out the module that contains it.
- Figure out if the module has data in the domain-neutral store or not.
- If so, use that to get the domain local module data
- Otherwise, use the app domain’s domain local module data.
- Using the DLM data, use the GCStaticDataStart, or NonGCStaticDataStart (for non-reference types) to find the base offset
- Add the field’s static offset to the base offset to get where in memory the field is
- Read from the memory offset to get the field value.
Next up: more details on implementing ClrProcess