如何获取堆栈帧的执行对象?

时间:2009-05-20 17:50:18

标签: c# reflection stack-trace stackframe

使用反射时,可以使用System.Diagnostics.StackTrace获取调用堆栈(除了它可以是由JIT优化引起的粗略近似)并检查包含的StackFrame对象。

如何获取对堆栈帧中的方法正在执行的对象(this-pointer)的引用?

我知道我可以通过在堆栈框架对象上调用GetMethod()来获取MethodBase,但我正在寻找的东西是GetObject()(如果方法是静态的话,自然会返回null) 。看起来堆栈帧对象只能查询静态确定的信息,例如方法信息,原始文件等。

VS调试器知道(虽然它可能使用另一种获取调用堆栈跟踪的方法),因为可以双击调用堆栈窗口中的任何堆栈帧并查看本地和类字段的值。

编辑: 澄清一下:我想要调用该方法的对象实例 。 I.e。:如果在调用堆栈的某个地方的对象实例A上调用方法Foo(),并且它级联到我执行堆栈跟踪的方法,我想从我执行堆栈跟踪的位置获得对A的引用。 (不是方法库的声明类型)

3 个答案:

答案 0 :(得分:6)

我很确定这是不可能的。原因如下:

  1. 这可能会破坏类型的安全性,因为任何人都可以查找一个框架,无论他们正在执行哪个AppDomain \ Thread或者他们有权限,都可以获取该对象。

  2. 'this'(C#)标识符实际上只是实例方法的参数(第一个),所以实际上静态方法和实例方法没有区别,编译器就是魔术将正确的this传递给实例方法,这当然意味着您需要访问所有方法参数才能获取this对象。 (StackFrame不支持)

  3. 有可能通过使用unsafe代码获取实例方法的第一个参数的指针,然后将其转换为正确的类型,但我不知道如何做到这一点,只是一个想法

    BTW你可以想象实例方法在被编译成C#3.0扩展方法之后,它们将this指针作为它们的第一个参数。

答案 1 :(得分:3)

可以获得对thiscall对象的引用,但不能仅使用.NET代码。必须涉及本机代码。即使使用动态类和System.Relection.Emit命名空间.NET也没有工具来访问另一个方法评估堆栈和参数。

另一方面,如果您反汇编.NET方法,您可以看到此引用根本没有在物理堆栈上传递。 Thiscall引用存储在ECXRCX for x64)寄存器中。因此,有可能从您的方法爬上堆栈到您想要获取thiscall对象的方法。然后在该方法的机器代码中查找保存寄存器ECX(RCX)的指令,并从该指令获取该引用所在的相对地址。

当然,在x32和x64应用中,攀爬方法有很大不同。要生成这样的函数,您不仅要使用C#而且要使用汇编代码,并且请记住x64下不允许使用内联汇编程序。它必须是一个完整的汇编程序模块。

答案 2 :(得分:-1)

我不确定我完全理解你想要什么,但是如果你想知道声明某个堆栈帧的方法的类型,我想这段代码会返回:

StackTrace trace = new StackTrace();    
Type methodOwner = trace.GetFrame(0).GetMethod().DeclaringType;

您当然需要传递您感兴趣的帧的索引(我使用0作为示例)。