【问题标题】:Resolving the tokens found in the IL from a dynamic method从动态方法解析在 IL 中找到的令牌
【发布时间】:2010-11-10 19:31:10
【问题描述】:

感谢 Hans Passant 在这里回答我的问题: How do I get an IL bytearray from a DynamicMethod?

我能够起床并跑步。我现在正在尝试解析在发出的 IL 中找到的元数据令牌,以查看正在调用哪些方法,或者不调用哪些方法。我能够解决方法主体中的下一个标记是调用。我正在使用来自Mono.Reflection 的 MethodBodyReader 的一些代码。

static byte[] GetILByteArray(Delegate @delegate){
   // does stuff mentioned in other thread
}
...
Expression<Action> foo = () => Console.WriteLine(0);
var compiled = foo.Compile();
var bytes = GetILByteArray(compiled);
int index =Array.FindIndex(bytes,b=>GetOpCode(b).OperandType == OperandType.InlineMethod);
var token = BitConverter.ToInt32(bytes,index+1);
compiled.Method.Module.ResolveMember(token);

抛出一个异常,指出该令牌在该域中是不可解析的。有人在这里有窍门吗?我应该尝试传入代表的泛型参数还是它们完全没用?

我目前正在考虑为表达式树的委托编写一个反编译器的想法,我真的很希望能够使用我自己编译的表达式树作为测试用例,因为我总是可以回到原来的并进行比较。

【问题讨论】:

  • 这样的项目对您有帮助吗:codeproject.com/KB/cs/… 它似乎在按照相同的方式工作,因此它的源代码可能包含您需要的内容。
  • 所以你正在使用它?我绝对不记得得到答案。帮助我重返工作岗位,我会帮助你,希望这是有道理的。
  • 您的答案的修改版本。大部分是正确的,我会把你标记为答案,但我认为烘焙版本是需要的。
  • 你搞清楚了吗?我也遇到过这个。
  • 我有一个解决方案,但它的反射太混乱了,让我想哭。你必须从IntPtrs 构造一个RuntimeTypeHandleRuntimeMethodHandle 等。参考源表明这是解决它的唯一真正方法。即将发布。

标签: c# dynamicmethod


【解决方案1】:

答案是您必须使用DynamicMethod.m_resolver 来解析动态方法的令牌,而不是使用Module。这是有道理的,因为DynamicMethod.m_resolver.m_codewhere you should be getting the IL byte array from

这很困难,因为DynamicResolver.ResolveToken 返回IntPtr 输出并将它们转换回RuntimeTypeHandleRuntimeMethodHandle 等需要大量的反思。此解决方案不太可能在 .NET 4.x 运行时中断,但请留意任何主要版本更改。

没有简洁的表达方式。

定义并使用此接口而不是 Module 来解析令牌:

public interface ITokenResolver
{
    MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    byte[] ResolveSignature(int metadataToken);
    string ResolveString(int metadataToken);
}

对于非动态方法:

public sealed class ModuleTokenResolver : ITokenResolver
{
    private readonly Module module;

    public ModuleTokenResolver(Module module)
    {
        this.module = module;
    }

    public MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveMember(metadataToken, genericTypeArguments, genericMethodArguments);

    public Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveType(metadataToken, genericTypeArguments, genericMethodArguments);

    public FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);

    public MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);

    public byte[] ResolveSignature(int metadataToken) =>
        module.ResolveSignature(metadataToken);

    public string ResolveString(int metadataToken) =>
        module.ResolveString(metadataToken);
}

对于动态方法:

public sealed class DynamicMethodTokenResolver : ITokenResolver
{
    private delegate void TokenResolver(int token, out IntPtr typeHandle, out IntPtr methodHandle, out IntPtr fieldHandle);
    private delegate string StringResolver(int token);
    private delegate byte[] SignatureResolver(int token, int fromMethod);
    private delegate Type GetTypeFromHandleUnsafe(IntPtr handle);

    private readonly TokenResolver tokenResolver;
    private readonly StringResolver stringResolver;
    private readonly SignatureResolver signatureResolver;
    private readonly GetTypeFromHandleUnsafe getTypeFromHandleUnsafe;
    private readonly MethodInfo getMethodBase;
    private readonly ConstructorInfo runtimeMethodHandleInternalCtor;
    private readonly ConstructorInfo runtimeFieldHandleStubCtor;
    private readonly MethodInfo getFieldInfo;

    public DynamicMethodTokenResolver(DynamicMethod dynamicMethod)
    {
        var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod);
        if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized.");

        tokenResolver = (TokenResolver)resolver.GetType().GetMethod("ResolveToken", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(TokenResolver), resolver);
        stringResolver = (StringResolver)resolver.GetType().GetMethod("GetStringLiteral", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(StringResolver), resolver);
        signatureResolver = (SignatureResolver)resolver.GetType().GetMethod("ResolveSignature", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(SignatureResolver), resolver);

        getTypeFromHandleUnsafe = (GetTypeFromHandleUnsafe)typeof(Type).GetMethod("GetTypeFromHandleUnsafe", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(IntPtr) }, null).CreateDelegate(typeof(GetTypeFromHandleUnsafe), null);
        var runtimeType = typeof(RuntimeTypeHandle).Assembly.GetType("System.RuntimeType");

        var runtimeMethodHandleInternal = typeof(RuntimeTypeHandle).Assembly.GetType("System.RuntimeMethodHandleInternal");
        getMethodBase = runtimeType.GetMethod("GetMethodBase", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { runtimeType, runtimeMethodHandleInternal }, null);
        runtimeMethodHandleInternalCtor = runtimeMethodHandleInternal.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(IntPtr) }, null);

        var runtimeFieldInfoStub = typeof(RuntimeTypeHandle).Assembly.GetType("System.RuntimeFieldInfoStub");
        runtimeFieldHandleStubCtor = runtimeFieldInfoStub.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(IntPtr), typeof(object) }, null);
        getFieldInfo = runtimeType.GetMethod("GetFieldInfo", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { runtimeType, typeof(RuntimeTypeHandle).Assembly.GetType("System.IRuntimeFieldInfo") }, null);
    }

    public Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        return getTypeFromHandleUnsafe.Invoke(typeHandle);
    }

    public MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        return (MethodBase)getMethodBase.Invoke(null, new[]
        {
            typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
            runtimeMethodHandleInternalCtor.Invoke(new object[] { methodHandle })
        });
    }

    public FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        return (FieldInfo)getFieldInfo.Invoke(null, new[]
        {
            typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
            runtimeFieldHandleStubCtor.Invoke(new object[] { fieldHandle, null })
        });
    }

    public MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        if (methodHandle != IntPtr.Zero)
        {
            return (MethodBase)getMethodBase.Invoke(null, new[]
            {
                typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
                runtimeMethodHandleInternalCtor.Invoke(new object[] { methodHandle })
            });
        }

        if (fieldHandle != IntPtr.Zero)
        {
            return (FieldInfo)getFieldInfo.Invoke(null, new[]
            {
                typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
                runtimeFieldHandleStubCtor.Invoke(new object[] { fieldHandle, null })
            });
        }

        if (typeHandle != IntPtr.Zero)
        {
            return getTypeFromHandleUnsafe.Invoke(typeHandle);
        }

        throw new NotImplementedException("DynamicMethods are not able to reference members by token other than types, methods and fields.");
    }

    public byte[] ResolveSignature(int metadataToken)
    {
        return signatureResolver.Invoke(metadataToken, 0);
    }

    public string ResolveString(int metadataToken)
    {
        return stringResolver.Invoke(metadataToken);
    }
}

这是检测动态方法的方法,以及一些辅助方法:

public static class ReflectionExtensions
{
    public static bool IsLightweightMethod(this MethodBase method)
    {
        return method is DynamicMethod || typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic).IsInstanceOfType(method);
    }

    public static ITokenResolver GetTokenResolver(this MethodBase method)
    {
        var dynamicMethod = TryGetDynamicMethod(method as MethodInfo) ?? method as DynamicMethod;
        return dynamicMethod != null
            ? new DynamicMethodTokenResolver(dynamicMethod)
            : (ITokenResolver)new ModuleTokenResolver(method.Module);
    }

    public static byte[] GetILBytes(this MethodBase method)
    {
        var dynamicMethod = TryGetDynamicMethod(method as MethodInfo) ?? method as DynamicMethod;
        return dynamicMethod != null
            ? GetILBytes(dynamicMethod)
            : method.GetMethodBody()?.GetILAsByteArray();
    }

    public static byte[] GetILBytes(DynamicMethod dynamicMethod)
    {
        var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod);
        if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized.");
        return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver);
    }

    public static DynamicMethod TryGetDynamicMethod(MethodInfo rtDynamicMethod)
    {
        var typeRTDynamicMethod = typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic);
        return typeRTDynamicMethod.IsInstanceOfType(rtDynamicMethod)
            ? (DynamicMethod)typeRTDynamicMethod.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(rtDynamicMethod)
            : null;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多