17.2 debug-on-entry

当函数出现错误时,Emacs 会自动启动调试器。

顺便一提,在所有版本的 Emacs 中你都可以手动启动调试器;这样做的好处是,即使代码中没有错误,调试器也照样可以运行。毕竟有时候你的代码是完全没有 Bug 的!

通过调用 debug-on-entry,你可以在调用函数时直接进入调试器。

输入:

M-x debug-on-entry RET triangle-bugged RET

接下来,执行下面的表达式:

(triangle-bugged 5)

所有版本的 Emacs 都会创建一个 *Backtrace* 缓冲区,并提示即将开始执行 triangle-bugged 函数:

---------- Buffer: *Backtrace* ----------
Debugger entered--entering a function:
* triangle-bugged(5)
  eval((triangle-bugged 5) nil)
  eval-expression((triangle-bugged 5) nil nil 127)
  funcall-interactively(eval-expression (triangle-bugged 5) nil nil 127)
  call-interactively(eval-expression nil nil)
  command-execute(eval-expression)
---------- Buffer: *Backtrace* ----------

*Backtrace* 缓冲区中按 d。Emacs 会执行 triangle-bugged 内的第一个表达式,缓冲区内容会变成这样:

---------- Buffer: *Backtrace* ----------
Debugger entered--beginning evaluation of function call form:
* (let ((total 0)) (while (> number 0) (setq total ...)
        (setq number ...)) total)
* triangle-bugged(5)
  eval((triangle-bugged 5))
  eval((triangle-bugged 5) nil)
  eval-expression((triangle-bugged 5) nil nil 127)
  funcall-interactively(eval-expression (triangle-bugged 5) nil nil 127)
  call-interactively(eval-expression nil nil)
  command-execute(eval-expression)
---------- Buffer: *Backtrace* ----------

现在,再次慢慢按 d,连续按八次。每按一次 d,Emacs 就会执行函数定义中的下一个表达式。

最终,缓冲区会显示如下内容:

---------- Buffer: *Backtrace* ----------
Debugger entered--beginning evaluation of function call form:
* (setq number (1= number))
* (while (> number 0) (setq total (+ total number))
        (setq number (1= number)))
* (let ((total 0)) (while (> number 0) (setq total ...)
        (setq number ...)) total)
* triangle-bugged(5)
  eval((triangle-bugged 5) nil)
  eval-expression((triangle-bugged 5) nil nil 127)
  funcall-interactively(eval-expression (triangle-bugged 5) nil nil 127)
  call-interactively(eval-expression nil nil)
  command-execute(eval-expression)
---------- Buffer: *Backtrace* ----------

最后,再按两次 d 之后,Emacs 就会触发错误,*Backtrace* 缓冲区最上方两行会显示:

---------- Buffer: *Backtrace* ----------
Debugger entered--Lisp error: (void-function 1=)
* (1= number)
...
---------- Buffer: *Backtrace* ----------

通过按 d,你可以单步跟踪函数的执行过程。

*Backtrace* 缓冲区中按 q 可以退出调试,但并不会取消 debug-on-entry

要取消 debug-on-entry 的效果,调用 cancel-debug-on-entry 并指定函数名即可,如下:

M-x cancel-debug-on-entry RET triangle-bugged RET

(如果你正在 Info 中阅读本文,请现在取消 debug-on-entry。)