Adding a new managed class to Rotor (that interacts with the EE)
I haven't actually posted anything technical to this blog yet - so I figured I'd hack
together a piece of source (with the internal help of the CLR devs) that illustrates
something semi-cool, yet can be extended by those that are interested in continuing
the work. The source diff shows how to add a managed class to Rotor that fcall's in
to the runtime and extracts runtime information we wouldn't otherwise have access
to. The diff is here
[addNewFCall.diff]. I've also included C# code to use the new functionality here
[rotorfcallexamplecs.zip].
Very brief overview of the diff
The managed class we're adding is called MethodBody, and hangs off the System.Reflection
namespace. The idea is get information about a method's metadata at runtime, in this
case, we're getting the methods maximum stack size, as defined in the ECMA Partition
II spec. We achieve this by reflecting over a method using MethodInfo, getting it's
handle and calling on our new class to do the work. Remember, you'll need to have
a look at the diff to get a complete understanding of what we're trying to do, but
here's the quick overview:
We modify \bcl\sources to include the MethodBody.cs file we're defining below,
so that it can be compiled into mscorlib.dll.
**
\bcl\system\reflection\MethodBody.cs
namespace System.Reflection
{
using System;
using System.Runtime.InteropServices;
using CultureInfo
= System.Globalization.CultureInfo;
[Serializable()]
public sealed class MethodBody
{
private int maxStackSize;
//
only called from within the EE
private MethodBody() {}
public int MaxStackSize
{ get { return maxStackSize;
} }
}
}
We get the MethodBody of a method through the MethodHandle of a MethodInfo object.
MethodHandle is a struct defined in runtimemethodhandle.cs in the bcl\reflection directory.
We add our GetMethodBody() call here:
**
\bcl\system\runtimemethodhandle.cs
[MethodImpl(MethodImplOptions.InternalCall)]
public extern MethodBody
GetMethodBody();
Then we define the fcall hookup in \vm\ecall.cpp:
\vm\ecall.cpp
static
ECFunc gCOMMethodHandleFuncs[] =
{
...
{FCFuncElement("GetMethodBody", NULL, (LPVOID) COMMember::GetMethodBody)},
};
Now we define the unmanaged GetMethodBody class:
\vm\commember.h
class MethodBody
: Object
{
private:
MethodBody() { }
MethodBody(MethodBody &r) {}
public:
INT32 maxStackSize;
};
...
Define where the work will happen:
\vm\commember.h
static FCDECL1(MethodBody*, GetMethodBody,
MethodDesc **ppMethod);
And the real work. The unmanaged implementation of GetMethodBody. This code grabs
what we need, and fills the managed class with all the info, making a working MethodBody
object with the correct MaxStackSize of the method.
\vm\commember.cpp
FCIMPL1(MethodBody *, COMMember::GetMethodBody,
MethodDesc **ppMethod)
{
MethodDesc* pMethod = *ppMethod;
METHODBODYREF MethodBodyObj = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0();
GCPROTECT_BEGIN(MethodBodyObj);
TypeHandle thMethodBody(g_Mscorlib.FetchClass(CLASS__METHOD_BODY));
MethodBodyObj = (METHODBODYREF)AllocateObject(thMethodBody.GetMethodTable());
Module* pModule = pMethod->GetModule();
COR_ILMETHOD_DECODER MethodILHeader(pMethod->GetILHeader(), pModule->GetMDImport(),
TRUE);
MethodBodyObj->maxStackSize = MethodILHeader.GetMaxStack();
GCPROTECT_END();
HELPER_METHOD_POLL();
HELPER_METHOD_FRAME_END();
return (MethodBody*)OBJECTREFToObject(MethodBodyObj);
}
FCIMPLEND
Remember, the brief overview is just that, brief. To achieve a working implementation,
you'll need to tell the runtime a bit more about what you're doing. Check out/apply
the diff to have a real look under the hood.
I'd love to see someone extend the MethodBody managed/unmanaged class to retrieve
the method body IL in say... Byte[] array format? Any takers? Feel free to post it
in the comments section. ;)
Comments
- Anonymous
December 18, 2003
Extending GetMethodBody to get the method code is surprisingly easy! I've put the code and written some notes on my WIki at http://www.dcooney.com/wiki/ow.asp?GetMethodBody . This adds a public byte[] GetIL() method to MethodBody. I haven't tried calling this for non-IL methods... :) - Anonymous
January 20, 2009
PingBack from http://www.hilpers-esp.com/541084-obtener-codigo-del-executable-net