代码之家  ›  专栏  ›  技术社区  ›  Iguananaut

如何找到与执行CPython堆栈帧相关联的C堆栈指针

  •  -1
  • Iguananaut  · 技术社区  · 6 年前

    如果这有助于缩小问题的范围,那么这个问题实际上更多的是关于cpythonapi,以及我是否遗漏了一些获取所需信息的方法。我不是在寻求更广泛问题的解决方案,而是在处理更广泛的问题时,我遇到了一个关于CPython的特定问题,它是否提供了一种对我来说不明显的方式来获取一些特定的信息。我只是把问题加上了标签 关于C或特定体系结构/平台的一般性问题。

    另请参见下面关于使用 PyEval_SetTrace ,虽然我希望他们会是一个更好的方式。作为另一个例子,存在一个 PyMain_GetArgcArgv 在这里可以做到,但是 只有 如果Python解释器是从 python PyMain_GetArgcArgv公司 不作为API的一部分进行记录。


    我希望能够找到C堆栈帧的地址(即 __builtin_frame_address(0)

    概括地说,上下文是我正在包装一个C库,它使用一个模糊的自定义垃圾收集器,它需要一个指向堆栈底部的指针——至少可以追溯到有局部变量指向GC应该跟踪的对象。理想情况下,我可以标记堆栈的底部一次;在本例中,由于它被包装在一个Python模块中,所以它足够深入到最外层的Python堆栈框架。最好的替代方法是在每次输入对库的调用时手动标记堆栈底部,但这并不理想,而且还需要修补库(无论哪种方式都可能需要),因为它目前只允许在初始化函数期间设置堆栈底部地址一次。

    PyEval_EvalFrameEx

    很明显,这都是CPython特有的,这对我来说没问题。既然如此,从技术上讲,CPython没有理由 PyFrameObject PyFrameObject 这样我就可以把它和一个C堆栈帧联系起来。例如,对于这个应用程序来说,如果在 PyFrameObject 喜欢 f_cstack 它们的用法如下:

    PyObject* _Py_HOT_FUNCTION
    _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
    {
        ...
        f->f_executing = 1;
        f->f_cstack = &f;
        ...
    }
    

    f f 并将其地址存储在堆栈上。不幸的是,目前我找不到这样的东西。

    PyEval_SetTrace 处理程序,它将在输入Python堆栈帧时被调用,从而使我有机会从那里查找堆栈。但实际上对于手头的应用程序,我只需要能够找到“最外层” 皮埃瓦尔·埃瓦夫拉梅克斯 调用,对于任何正在运行的Python代码都将有一个调用。所以安装一个跟踪回调并不一定能让我做到这一点,而且我不需要为每次函数调用都增加额外的开销。

    我担心目前还没有一个好的解决办法,尽管如果有的话会很方便。

    (另外,我只关心主堆栈,而不关心线程,尽管任何在主线程上工作的解决方案都可能在辅助线程上有类似的解决方案)。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Basile Starynkevitch    6 年前

    一般来说,原则上,您可能无法总是做您想做的事情(众所周知,在某些情况下,C实现甚至可能不需要任何调用堆栈)。因为有时编译器喜欢 GCC Clang )能够 tail-call 编译程序 optimizations calling conventions gcc -fomit-frame-pointer -m32 on 32位x86)使遍历 call stack (至少,没有 额外的

    实际上,您应该研究使用GNU backtrace 函数和更好的伊恩·泰勒 libbacktrace libbacktrace 库解析 DWARF 调试信息(因此它可能是特定于Linux的,可能在Windows上不起作用)。在Linux上, dladdr(3) 能够获得接近给定地址的符号名。

    因此,最好使用 -g gcc g++ . 记住GCC能够处理 二者都 和优化标志 -O2

    为了打猎 memory leaks (在一些评论中间接提到,但问题本身没有提到),有些工具是可用的(例如。 valgrind ). 问它们是否适合混合Python+C程序则是另一个问题。

    垃圾收集的bug很难找到(我自己也写了几个gc,尤其是在我过时的版本中) GCC MELT 在我的 bismon -,所以我是凭经验说的;也要读 GC handbook ). 将一个GC与另一个GC混合(Python refcounting机制是一种GC机制)既痛苦又脆弱。可能更合理 在实践中 使用将软件拆分为多个进程 inter-process communication 设施(这些是操作系统特有的)。

    CPython free software fork 它要补充 libbacktrace 内部支持(从技术上讲,这样做应该相当容易)。