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

发布于 2024-07-19 07:30:34 字数 949 浏览 5 评论 0原文

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

示例:

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 分析并自动生成文档和待办事项列表以进行具体组装。

I have several special methods, and I want analyze they calls in compiled assembly.

Example:

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

From this compiled code I want get the argument values { "Should create array of ", MyClass, " with specified size." }.
I tried use Cecil from Mono, and I found the instructions for call "ToDo" method. But now am I confused how to identify instruction with argument values.

I know, there can be complex situation, and some argument's value can not be resolved. But I need resolve only constant values - it's enough for my purpose.

Thanks.

EDIT:
The "ToDo" method (and similar ones) should be used as alternative to comments ( //, /* ... */ ), and after compilation, should be IL analyzed and autogenerated documentation and todo-list for concrete assembly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱花落人离去 2024-07-26 07:30:34

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

编译:(

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

添加“x”以强制其使用参数重载)

给出

.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. 找到对“我的方法”的调用。
  2. 找到最近的前一个 newarr 对象,
  3. 获取它们之间的所有 ldstr 和 ldtoken 并假设它们是参数。

这很粗糙,但可能足以满足您的需求。

AOP 风格的方法将通过简单地检测每个调用以转储值来在运行时为您提供所需的内容,但在编译时,上面的方法是仅给出 IL 的唯一现实选择。

显式创建的数组(可能距离调用站点更远,甚至在不同的方法/构造函数/类中)

生成的代码在发布版本中可能非常不同,您将无法发现自动生成的数组与某人自己 编辑后应注意为什么要这样做,基于属性的注释是一个更好的解决方案,我不明白为什么当您可以直接属性时要在方法中执行此操作...

The code generation is somewhat confusing but can be done for simple cases:

compiling:

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

(adding "x" to force it to use a params overload)

gives

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

So you have to do is parse the il to detect the arguments being pushed into the compiler generated array. a heristic that is fragile but might be sufficient it to say:

  1. find call to 'my method'.
  2. find nearest previous newarr object
  3. take all ldstr and ldtoken in between these and assume they are the arguments.

This is rough but may be sufficient for your needs.

An AOP style approach will get you what you want at runtime by simply instrumenting every call to dump the values but at sompile time the approach above is your only realistic option given only the IL.

The code generated may be very different in Release builds, You will be unable to spot the auto generated array verses someone explicitly creating it themselves (which may be further away from the call site or even in a different method/constructor/class.

Proviso

I should note after your edit for why you want to do this that Attribute based annotations are a far better solution, I cannot see why you would want to do this in the method when you can attribute it directly...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文