【发布时间】:2018-12-04 10:21:01
【问题描述】:
更新:如果它有助于缩小任何人的问题范围,那么这个问题实际上更多是关于 CPython API 以及我是否错过了某种方式来获取我需要的信息。我不是要求解决更广泛的问题,而是在解决更广泛的问题时,我遇到了一个关于 CPython 的特定问题,以及它是否提供了一种对我来说并不明显的方式来获取某些特定信息。我只标记了问题 c,因为它本质上需要一些 C 专业知识,但它不是关于 C 或特定架构/平台的一般问题。
另请参阅下面关于使用PyEval_SetTrace 的一种可能方法的注释,尽管我希望它们可能是一种更好的方法。作为另一个例子,有一个PyMain_GetArgcArgv 可以在这里解决问题,但只有如果Python 解释器是从python 可执行文件而不是嵌入的(这可能是一个可接受的限制)启动的。此外,PyMain_GetArgcArgv 也没有记录为 API 的一部分。
我希望能够找到与 Python 堆栈帧最密切相关的 C 堆栈帧的地址(即为该平台适当定义的 __builtin_frame_address(0))。特别是,我想找到与 Python 函数调用相关联的最外层框架(或靠近它的框架),以便在下面更好地定义。
总而言之,上下文是我正在包装一个 C 库,该库使用一个晦涩的自定义垃圾收集器,它需要一个指向堆栈底部的指针——至少只要有局部变量指向到应该被 GC 跟踪的对象。理想情况下,我可以标记堆栈的底部一次;在这种情况下,因为它被包装在一个 Python 模块中,所以向下到最外层的 Python 堆栈框架就足够了。最好的替代方法是在输入对库的调用时手动标记堆栈底部,但这并不理想,并且还需要修补库(可能需要任何一种方式),因为它目前只允许设置堆栈底部地址一次,在初始化函数期间。
Python 堆栈帧与 C 堆栈帧究竟是如何关联的,目前尚不明确,因为从技术上讲,两者之间没有固定的联系。但是,出于手头的实际目的,它将处于或接近(取决于编译器优化等)正在执行的帧的 PyEval_EvalFrameEx 调用(我对当前不在调用堆栈上的帧不感兴趣因为在那种情况下这显然是一个毫无意义的问题)。
这显然是非常特定于 CPython 的,这对我的目的来说是可以的。在这种情况下,从技术上讲,CPython PyFrameObject struct 实现不能在其成员之一上携带这样的信息是没有理由的,但据我所知,PyFrameObjects 上没有任何具体存储可以让我将其与 C 堆栈帧相关联。例如,就本应用程序而言,如果PyFrameObject 中的某些内容(例如f_cstack)的使用如下:
PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
{
...
f->f_executing = 1;
f->f_cstack = &f;
...
}
这将工作 AFAICT——即使 f 通常在寄存器中传递,我的 gcc 将通过将 f 推入堆栈并将其地址存储在堆栈中来处理这样的代码。不幸的是,目前我找不到这样的东西。
我能想到的最好的主意是注册一个PyEval_SetTrace 处理程序,它会在进入Python 堆栈帧时被调用,从而让我有机会从那里围绕堆栈进行根植。但实际上对于手头的应用程序,我只需要能够找到“最外层”PyEval_EvalFrameEx 调用,任何正在运行的 Python 代码都会有一个调用。所以安装跟踪回调不一定能让我明白这一点,而且我不需要每个函数调用都需要额外的开销。
我担心目前没有很好的解决方案,但如果有的话会很方便。
(PS 我也只关心主堆栈,而不是线程,尽管任何适用于主线程的解决方案都可能在辅助线程上具有类似的解决方案)。
【问题讨论】:
-
在哪个操作系统上?
-
假设这是一个独立于操作系统的问题,因此它不能依赖特定的二进制格式或任何东西。我正在添加一个小更新。
-
在实践中,它不是操作系统中立的
-
可能是XY problem...您遇到的实际问题是什么?这应该在问题中提到
-
这不是 XY 问题。实际问题还有其他(尽管不太令人满意)的解决方案,我只是好奇是否有人足够聪明地找到我无法解决问题的解决方案。感谢您尝试提供帮助,但 实际 问题如所述。