17.4 edebug 源码级调试器

Edebug 是一个源码级调试器。Edebug 通常显示你正在调试的代码的源码,左边有一个箭头,指示你当前执行的是哪一行。

你可以逐行地走过函数的执行,或者快速运行直到达到一个断点,在那里停止执行。

有关 Edebug 的详细信息,请参阅Edebug in GNU Emacs Lisp 参考手册

下面是一个有bug的 triangle-recursively 函数定义。参见See 替代计数的递归, 进行查看。

(defun triangle-recursively-bugged (number)
  "返回1到NUMBER(包括)之间数字的和,使用递归。"
  (if (= number 1)
      1
    (+ number
       (triangle-recursively-bugged
        (1= number)))))               ; 这里有错误。

通常,你会通过将光标定位在函数的闭括号之后,然后输入 C-x C-eeval-last-sexp),或者将光标定位在定义内部,然后输入 C-M-xeval-defun)来安装这个定义。 (默认情况下,eval-defun 命令仅在 Emacs Lisp 模式或 Lisp 交互模式下工作。)

然而,为了准备这个函数定义以供 Edebug 使用,你必须首先使用不同的命令进行仪器化。你可以将光标定位在定义内部或之后,然后输入

M-x edebug-defun RET

这将导致 Emacs 在需要时自动加载 Edebug(如果尚未加载),并正确地仪器化该函数。

在仪器化函数之后,将光标放在以下表达式之后,然后输入 C-x C-eeval-last-sexp):

(triangle-recursively-bugged 3)

你将跳转回 triangle-recursively-bugged 的源码,光标定位在函数的 if 行的开头。此外,你将在该行的左侧看到一个箭头。箭头标记了函数执行的行。在下面的示例中,我们使用‘=>’显示箭头;在窗口系统中,你可能会在窗口边缘看到箭头作为一个实心三角形。

=>∗(if (= number 1)

在示例中,点的位置显示为 ‘’(在印刷书籍中,它显示为一个五角星)。

如果现在按下 SPC 键,点将移动到下一个要执行的表达式;该行将如下所示:

=>(if ∗(= number 1)

随着你继续按下 SPC,点将从一个表达式移动到另一个表达式。与此同时,每当一个表达式返回一个值时,该值将显示在回显区域。例如,当你将点移到 number 后面时,你将看到以下内容:

Result: 3 (#o3, #x3, ?\C-c)

这意味着 number 的值是3,即八进制三,十六进制三,和 ASCII 控制字符C(字母表的第三个字母,如果你需要知道这些信息)。

你可以继续移动代码,直到到达包含错误的行。在评估之前,该行看起来像这样:

=>        ∗(1= number)))))               ; 这里有错误。

当你再次按下 SPC 时,将会产生一个错误消息,说:

Symbol's function definition is void: 1=

这就是bug。

按下 q 退出 Edebug。

要从函数定义中删除仪器化,只需使用不对其进行仪器化的命令重新评估它。例如,你可以将光标放在定义的闭括号之后,然后输入 C-x C-e

Edebug 不仅仅能够与你一起逐步执行函数。你可以设置它,让它自己快速执行,只在错误或指定的停止点停下;你可以让它显示各种表达式的变化值;你可以了解一个函数被调用了多少次,等等。

有关 Edebug 的详细信息,请参阅Edebug in GNU Emacs Lisp 参考手册