在C python中,访问字节码评估堆栈 [英] In C python, accessing the bytecode evaluation stack

查看:114
本文介绍了在C python中,访问字节码评估堆栈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出一个C Python框架指针,如何查看任意评估堆栈条目? (可以通过 locals()找到一些特定的堆栈条目,我说的是其他堆栈条目。)



不久前,我问了一个更广泛的问题:



获取C python exec参数字符串或访问评估堆栈



但是在这里,我想着重于能够在运行时读取CPython堆栈条目。



我将采用在CPython 2.7或Python 3.3之后的任何Python上均可使用的解决方案。但是,如果您有其他功能,请分享,并且如果没有更好的解决方案,我会接受。



我宁愿不修改C Python代码。 在Ruby中,我实际上已经这样做了以得到我想要的东西。我可以根据经验说,这可能不是我们想要的工作方式。但是,如果没有更好的解决方案,我会考虑的。 (我对SO点的理解是,无论哪种方式,我都会以失败的方式失去它。因此,我很高兴看到它表现出最大的精神和意愿去看待这一点,并假设它可行。) / p>

更新:请参见user2357112 tldr的评论; 基本上,这很难做到。 (不过,如果您认为自己有尝试的力量,请务必这样做。)



因此,让我将范围缩小到这个更简单的范围我认为可行的问题:



给出一个python堆栈框架,例如 inspect.currentframe(),找到评估堆栈的开始。在该结构的C版本中,这是 f_valuestack 。然后,我们需要使用Python中的一种方法从那里读取Python值/对象。



更新2 ,赏金的期限已经结束,没有人(包括我自己的简要答案)提供具体的代码。我觉得这是一个好的开始,现在我对情况的了解比以前要多得多。在强制性的描述为什么您应该有赏金的描述中,我列出了其中的一种选择,以引起更多对这个问题的关注,并且在某种程度上,对于以前的化身还没有十几种观点。问题,当我键入此内容时,它被查看了不到190次。所以这是成功的。但是...



如果将来有人决定进一步携带此物品,请与我联系,我将设立另一个赏金。



谢谢。

解决方案

稍后添加说明:请参阅crusaderky的 get_stack.py ,可以在此处将其解决。 p>

这里有两个潜在的局部解决方案,因为这个问题没有简单明显的答案,除了:



  • 修改CPython解释器或通过:

  • 之前插入字节码,例如通过 byteplay


感谢user2357112对问题的难度有所启发,并对以下内容进行了说明:



  • 运行时使用的各种Python堆栈,

  • 非连续的评估堆栈,

  • 评估堆栈和

  • 仅作为C局部
    变量存在的堆栈指针顶部(在运行时,可能仅保存在寄存器的
    值中)。


现在有潜在的解决方案。


第一个解决方案是编写一个C扩展名以访问底部 f_valuestack (不是顶部)。从中您可以访问值,这也必须在C扩展中进行。这里的主要问题是堆栈底部,因此要了解哪个条目是您感兴趣的顶部或底部堆栈。代码在函数中记录了最大堆栈深度。


C扩展将包装PyFrameObject,以便它可以访问未暴露的字段 f_valuestack 。尽管PyFrameObject可以从Python版本更改为Python版本(因此扩展程序可能必须检查正在运行的python版本),但它仍然是可行的。


使用抽象虚拟机来找出在<$ c $中存储的给定偏移量您将处于哪个输入位置c> last_i 。


对我来说,类似的用途是使用 real 但其他VM,例如Ned Batchhelder的字节流。它在Python中运行一个Python字节码解释器。


稍后再添加说明:为了支持Python 2.5 .. 3.7左右,我做了一些大的修改,现在称为< a href = https://github.com/rocky/x-python rel = nofollow noreferrer> x-python


这样做的好处是,由于它充当第二个VM,因此存储不会更改当前和实际CPython VM的运行。但是,您仍然需要处理与外部持久状态进行交互的事实(例如,跨套接字调用或文件更改)。而且字节扩展需要扩展到涵盖可能需要的所有操作码和Python版本。


顺便说一句,以统一的方式对字节码进行多版本访问(因为不仅字节码会有所变化,但访问它的例程也会有所变化),请参见 xdis


因此,尽管这不是通用解决方案,但它可能适用于试图弄清楚 EXEC 向上,在评估堆栈中短暂出现。


Given a C Python frame pointer, how do I look at arbitrary evaluation stack entries? (Some specific stack entries can be found via locals(), I'm talking about other stack entries.)

I asked a broader question like this a while ago:

getting the C python exec argument string or accessing the evaluation stack

but here I want to focus on being able to read CPython stack entries at runtime.

I'll take a solution that works on CPython 2.7 or any Python later than Python 3.3. However if you have things that work outside of that, share that and, if there is no better solution I'll accept that.

I'd prefer not modifying the C Python code. In Ruby, I have in fact done this to get what I want. I can speak from experience that this is probably not the way we want to work. But again, if there's no better solution, I'll take that. (My understanding wrt to SO points is that I lose it in the bounty either way. So I'm happy go see it go to the person who has shown the most good spirit and willingness to look at this, assuming it works.)

update: See the comment by user2357112 tldr; Basically this is hard-to-impossible to do. (Still, if you think you have the gumption to try, by all means do so.)

So instead, let me narrow the scope to this simpler problem which I think is doable:

Given a python stack frame, like inspect.currentframe(), find the beginning of the evaluation stack. In the C version of the structure, this is f_valuestack. From that we then need a way in Python to read off the Python values/objects from there.

update 2 well the time period for a bounty is over and no one (including my own summary answer) has offered concrete code. I feel this is a good start though and I now understand the situation much more than I had. In the obligatory "describe why you think there should be a bounty" I had listed one of the proffered choices "to draw more attention to this problem" and to that extent where there had been something less than a dozen views of the prior incarnation of the problem, as I type this it has been viewed a little under 190 times. So this is a success. However...

If someone in the future decides to carry this further, contact me and I'll set up another bounty.

Thanks all.

解决方案

Note added later: See crusaderky's get_stack.py which might be worked into a solution here.

Here are two potential solution partial solutions, since this problem has no simple obvious answer, short of:

  • modifying the CPython interpreter or by:
  • instrumenting the bytecode beforand such as via byteplay

Thanks to user2357112 for enlightenment on the difficulty of the problem, and for descriptions of:

  • the various Python stacks used at runtime,
  • the non-contiguous evaluation stack,
  • the transiency of the evaluation stack and
  • the stack pointer top which only lives as a C local variable (which at run time, might be or is likely only saved in the value of a register).

Now to potential solutions...

The first solution is to write a C extension to access f_valuestack which is the bottom (not top) of a frame. From that you can access values, and that too would have to go in the C extension. The main problem here, since this is the stack bottom, is to understand which entry is the top or one you are interested in. The code records the maximum stack depth in the function.

The C extension would wrap the PyFrameObject so it can get access to the unexposed field f_valuestack. Although the PyFrameObject can change from Python version to Python version (so the extension might have to check which python version is running), it still is doable.

From that use an Abstract Virtual Machine to figure out which entry position you'd be at for a given offset stored in last_i.

Something similar for my purposes would for my purposes would be to use a real but alternative VM, like Ned Batchhelder's byterun. It runs a Python bytecode interpreter in Python.

Note added later: I have made some largish revisions in order to support Python 2.5 .. 3.7 or so and this is now called x-python

The advantage here would be that since this acts as a second VM so stores don't change the running of the current and real CPython VM. However you'd still need to deal with the fact of interacting with external persistent state (e.g. calls across sockets or changes to files). And byterun would need to be extended to cover all opcodes and Python versions that potentially might be needed.

By the way, for multi-version access to bytecode in a uniform way (since not only does bytecode change a bit, but also the collections of routines to access it), see xdis.

So although this isn't a general solution it could probably work for the special case of trying to figure out the value of say an EXEC up which appear briefly on the evaluation stack.

这篇关于在C python中,访问字节码评估堆栈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆