代码之家  ›  专栏  ›  技术社区  ›  Michael B

从动态方法解析IL中找到的令牌

  •  5
  • Michael B  · 技术社区  · 15 年前

    感谢汉斯·帕桑特在这里回答我的问题: How do I get an IL bytearray from a DynamicMethod?

    我能站起来跑步。我现在正试图解析在发出的il中找到的元数据标记,看看调用了什么方法,或者没有调用什么方法。我能够解析方法体中的下一个标记是调用。我在用一些来自 Mono.Reflection 的方法BodyReader。

    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);
    

    引发一个异常,说明令牌在该域中不可解析。有人在这里耍把戏吗?我应该尝试传入委托泛型参数还是它们完全无用?

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

    1 回复  |  直到 9 年前
        1
  •  8
  •   Community Mohan Dere    9 年前

    答案是你必须使用 DynamicMethod.m_resolver 解析动态方法的标记,而不是使用 Module . 这是有道理的,因为 DynamicMethod.m_resolver.m_code where you should be getting the IL byte array from .

    这很难,因为 DynamicResolver.ResolveToken 收益率 IntPtr 把它们变成 RuntimeTypeHandle RuntimeMethodHandle 等需要相当多的思考。此解决方案不太可能在.NET4.x运行时中断,但请注意任何主要版本更改。

    只是没有简明扼要的方法来表达这一点。

    定义并使用此接口而不是 模块 用于解析令牌:

    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;
        }
    }