1

在我的python 调试器中,我有一种将字符串重新映射到文件名的方法,这样当您在调试器中单步执行 exec'd 函数时,您可以列出 pygmentized 行,或者通过realgud在 Emacs 等编辑器中查看它们。

因此,我希望能够在 CPython 在内部评估中停止时提取 exec 语句中的字符串。

我已经有了一种机制,可以在调用框架中回顾调用者是否为 anEXEC_STMT,并且我可以回顾一条指令以查看前一条指令是否为 say DUP_TOP。因此,如果我能想出一种方法来在调用时读取堆栈条目并给出评估的字符串,那么我就可以回家了。可能有一种方法可以进入 C 来获得这个,但我对 CPython 内部知识缺乏了解,并且不希望这样做。如果那里有一个包,也许我可以选择包含它。

CPython 已经提供了对函数参数和局部变量的访问,但当然,因为这是一个内置函数,所以它不会被记录为函数参数。

如果在如何做同样的事情上有其他想法,那也没关系。我觉得一个不太好的解决方案是以某种方式尝试重载或替换exec,因为调试器可以在游戏后期引入。

我知道 CPython2 和 CPython3 在这里可能会有些不同,但是从任何一个开始都可以。

4

2 回答 2

0

我想我现在找到了方法。

在调试器内部,我将调用堆栈上移一层以获取exec语句。然后我可以使用uncompyle6来获取源代码的语法树。(可能需要在 uncompyle6 中进行更改以使其更容易。)

调用点的树将具有类似exec_stmt -> expr .... 该表达式将具有表达式的文本,该文本不一定是表达式的值。表达式可以是一个常量字符串值,但也可以是复杂的,例如"foo" + var1.

因此,调试器可以在调试器的上下文中评估该字符串,该调试器知道如何在调用堆栈中评估表达式。

这仍然存在重新评估表达式可能会产生副作用的问题。但这是不好的编程习惯,对吧?;-)

因此,如果源不存在,我所做的只是从字节码中反编译代码。这样做的缺点是字节码中提到的行号并不总是与字节码中的行号对齐。为此,重新创建上述字符串的方法更好。

最后,我希望说明为什么编写一个真正好的调试器很难,以及为什么大量的调试器在即使是简单的事情上也有许多限制,比如在你当前停止的地方获取源文本。

一种完全不同的方法是提前停止并切换到可以访问堆栈的子解释器,如byterun (或一些经过适当修改的 Python C 模块)。

于 2016-05-02T08:39:39.493 回答
0

开源Thonny IDE具有 [子] 表达式评估步进。请参阅作者对 SO 问题Tracing Python expression evaluation step by step的回答。

于 2017-06-16T11:12:39.413 回答