可以在pdb中向后跳转吗?

74

我按下n键来评估一行代码后,如果出错了,我想回到之前的位置然后按s键进入函数内部执行。这有可能吗?

文档中写道:

j(ump) lineno 设置将要执行的下一行代码。只能在最底层的帧中使用。这允许您返回并重新执行代码,或者向前跳过不想运行的代码。


12
不行,PDB无法倒流时间。 - Martijn Pieters
@MartijnPieters,看一下我的编辑。文档说可以跳回到某一行,那么这样做或者跳回到上一行是不可能的吗? - YPCrumble
回到一个失败的函数并恢复导致失败的状态是两件不同的事情。 - Bartosz Marcinkowski
5
请注意该术语的警告。最底部框架的代码可以在上下文之外被操纵和运行,这就是“jump”所做的。没有发生时间倒流。如果你跳转以执行引发异常的函数,则异常不会被取消引发。 - Martijn Pieters
存在一个名为timetravelpdb的工具(在此处和此处被宣布过,更多信息请参见PyPi),但其唯一的文档是在Youtube视频中(!),而我还没有安装它。 - ShreevatsaR
我正在使用pydb和ddd分析代码,我尝试使用jump命令并且它有效。在我的情况下,执行两次函数没有问题,因此在这种情况下,这个jump命令非常有用! - Chan Kim
4个回答

65

GNU调试器GDB:它极其缓慢,因为它一次撤销一个机器指令。

Python调试器PDB:命令jump可以让你回到代码中,但不会撤销程序的状态。

对于Python语言,出于这个原因,扩展的Python调试器原型EPDB被创建。这是论文,这里有程序和代码

我以EPDB为起点,在我的MSc学位项目中创建了一个实时反向调试器。该论文可在网上找到:结合反向调试和实时编程以实现计算机编程中的视觉思维。在第1章和第2章中,我也涵盖了大多数历史方法的反向调试。


2
这篇论文看起来非常不错!虽然我还没有详细阅读,但作为专家,您认为目前在这个问题上提到的解决方案如何?您的 epdb vs timetravelpdb vs revdb in PyPy 怎么样? - ShreevatsaR
1
@ShreevatsaR 不确定你指的是哪篇论文,是Patrick Sabin早期的epdb论文还是我的后来的论文,两篇都在上面链接了。我已经超过2年没有关注反向调试的发展了,所以不确定。快速浏览后:timetravelpdb似乎与epdb非常相似,但功能较少,例如epdb不仅管理程序状态,而且管理外部/环境状态(在某种程度上),以确保确定性。Revdb使用记录-重放方法,也似乎不管理外部状态。记录-重放和快照(我更喜欢)方法都有优点,如我在论文中所解释的那样。 - Abraham
1
有关epdb的文档或教程吗? - Statham
@Statham 我也对 epdb 的教程感兴趣。 - test30

12

PyPy已经开始实现RevDB,支持反向调试。

截至2017年2月,它仍处于alpha阶段,仅支持Python 2.7,只能在Linux或OS X上运行,并需要您从特殊版本构建Python。 它也非常慢且使用大量RAM。引用Bitbucket页面的话:

请注意,日志文件通常以每秒1-2 MB的速度增长。假设大小不是问题,则限制因素为:

  • 重放时间。如果记录的执行时间超过几分钟,重放将非常缓慢。有时需要在单个会话中多次查看整个日志。 如果错误随机但很少发生,您应该运行记录几分钟,然后杀死进程并重复尝试,直到崩溃发生。
  • 重放时的RAM使用情况。重放的RAM需求比录制的RAM需求高10到15倍。 如果太多,您可以尝试在_revdb / process.py中使用较低的MAX_SUBPROCESSES值,但它始终会大几倍。

详细信息请查看PyPy博客,安装和使用说明请查看RevDB bitbucket页面


11

反向调试(返回以前记录的应用程序状态或向后单步调试)通常是汇编或C级别的调试器功能。例如,gdb可以做到:

https://sourceware.org/gdb/wiki/ReverseDebug

双向(或反向)调试

反向调试非常复杂,可能会导致性能下降 50,000 倍。 它还需要来自调试工具的广泛支持。 Python虚拟机不提供反向调试支持。

如果您正在交互式评估Python代码,则建议尝试IPython Notebook,它提供基于HTML的交互式Python shell。您可以轻松编写代码并混合匹配顺序。但是,它没有pdb调试支持。有ipdb,它为输入的调试命令提供更好的历史记录和搜索功能,但据我所知它也不直接进行后向跳转。


3

虽然你可能无法及时地逆转代码执行,但 pdb 的下一个最佳选择是堆栈帧跳转。

使用 w 查看您在堆栈帧中的位置(底部是最新的),并使用 u(p)d(own) 遍历堆栈帧以访问将您步入当前帧的函数调用所在的帧。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接