在IL中查找方法调用的参数值

时间:2009-05-13 12:08:16

标签: .net il mono.cecil

我有几个特殊方法,我想分析它们在编译汇编中调用。

示例:

public static class SrcHelper {
    [MySpecialMethod]
    [Conditional( "DEBUG" )]
    public static void ToDo( params object[] info ) {
        /* do nothing */
        /* this method is not called when code is compiled in RELEASE mode */
    }
}
// ... somewhere else in another assembly ...
Array CreateArraySampleMethod( int size ) {
    // This call has only informative character. No functionality is required.
    SrcHelper.ToDo( "Should create array of ", typeof( MyClass ), " with specified size." );
    throw new NotImplementedException();
}

从这个编译好的代码中我想得到参数值{“应该创建数组”,MyClass,“具有指定的大小”。 }。 我尝试使用Mono的Cecil,我找到了调用“ToDo”方法的说明。但现在我很困惑如何用参数值识别指令。

我知道,可能存在复杂的情况,而某些论证的价值无法解决。但我需要只解决不变的价值 - 这足以达到我的目的。

感谢。

修改 应该使用“ToDo”方法(和类似的方法)作为注释(//,/ * ... * /)的替代方法,并且在编译之后,应该进行IL分析并自动生成文档和todo-list以进行具体组装。 / p>

2 个答案:

答案 0 :(得分:1)

代码生成有点令人困惑,但可以在简单的情况下完成:

编译:

public static void Main(string[] args)
{
    Console.WriteLine("", // ignore this argument
       "Should create array of ", typeof(int), " with specified size." "x");
}

(添加“x”以强制它使用params重载)

给出

.method public hidebysig static void Main(string[] args) cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .maxstack 4
    .locals init (
        [0] object[] objArray)
    L_0000: ldstr ""
    L_0005: ldc.i4.4 
    L_0006: newarr object
    L_000b: stloc.0 
    L_000c: ldloc.0 
    L_000d: ldc.i4.0 
    L_000e: ldstr "Should create array of "
    L_0013: stelem.ref 
    L_0014: ldloc.0 
    L_0015: ldc.i4.1 
    L_0016: ldtoken int32
    L_001b: call class [mscorlib]System.Type 
                [mscorlib]System.Type::GetTypeFromHandle(
                    valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0020: stelem.ref 
    L_0021: ldloc.0 
    L_0022: ldc.i4.2 
    L_0023: ldstr " with specified size."
    L_0028: stelem.ref 
    L_0029: ldloc.0 
    L_002a: ldc.i4.3 
    L_002b: ldstr "x"
    L_0030: stelem.ref 
    L_0031: ldloc.0 
    L_0032: call void [mscorlib]System.Console::WriteLine(string, object[])
    L_0037: ret 
}

所以你要做的就是解析il以检测被推入编译器生成的数组的参数。一个脆弱的遗传,但可能足以说:

  1. 找到对'my method'的调用。
  2. 找到最近的newarr对象
  3. 将所有ldstr和ldtoken置于其间并假设它们是参数。
  4. 这很粗糙,但可能足以满足您的需求。

    AOP风格的方法可以通过简单地检测每个调用来转储值来获得你想要的运行时,但是在非常时间,上面的方法只是IL的唯一现实选择。

    在发布版本中生成的代码可能非常不同,您将无法发现自动生成的数组与某些人自己明确创建它(可能远离调用站点,甚至是在不同的方法/构造函数/类中)

    限制性条款

    在你编辑之后我应该注意你为什么要这样做,基于属性的注释是一个更好的解决方案,我不明白你为什么要在方法中做到这一点,你可以直接归属...

答案 1 :(得分:-1)

我不确定你的意思。但是,请注意您的函数实际上只获得一个参数:一个数组。这也是你在IL中得到的。 函数中,您可以遍历数组以获取其值:

public static void ToDo( params object[] info ) {
    foreach (object x in info)
        Console.WriteLine(x);
}