2010-11-10 58 views
5

感謝漢斯帕桑特這裏回答我的問題的標記: How do I get an IL bytearray from a DynamicMethod?解決從動態方法在IL發現

我能夠得到啓動和運行。我現在正在嘗試解析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); 

引發異常,表示令牌在該域中不可解析。任何人都有一個詭計嗎?我應該嘗試傳遞委託通用參數還是完全沒用?

我現在正忙着寫代碼表達式樹的反編譯器的想法,我真的很想能夠使用表達式樹,我自己編譯爲測試用例,因爲我總是可以回到原始和比較。

+0

會這樣幫你一個項目:http://www.codeproject.com/KB/cs/sdilreader.aspx?df=100&forumid=303062&exp=0&select=1833733 這似乎沿着相同的路線來工作,所以它的來源可能包含你需要的東西。 – Sorax 2010-11-10 19:52:34

+0

所以你使用它?我絕對不記得給它一個答案標記。幫助我回到我的工作,我會幫助你,希望是有道理的。 – 2010-11-10 20:02:12

+0

答案的修改版本。這大多是正確的,我會將你標記爲答案,但我認爲烘焙版本是需要的。 – 2010-11-10 21:08:45

回答

7

答案是您必須使用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; 
    } 
}