通过动态方法解析IL中发现的令牌

感谢Hans Passant在这里回答我的问题: 如何从DynamicMethod获取IL bytearray?

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

 static byte[] GetILByteArray(Delegate @delegate){ // does stuff mentioned in other thread } ... Expression 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); 

引发exception,说明该域中的令牌是不可解析的。 这里有人有诀窍吗? 我应该尝试传递代理通用参数还是完全没用?

我正在考虑为表达式树的代表编写反编译器的想法,我真的希望能够使用表达式树,我将自己编译为测试用例,因为我总是可以回到原始版本并进行比较。

答案是您必须使用DynamicMethod.m_resolver来解析动态方法的标记,而不是使用Module 。 这是有道理的,因为DynamicMethod.m_resolver.m_code是您应该从中获取IL字节数组的位置 。

这很难,因为DynamicResolver.ResolveToken返回IntPtr输出并将它们转回RuntimeTypeHandleRuntimeMethodHandle等需要相当多的reflection。 此解决方案不太可能在.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; } }