A Debug Workflow in Emacs

1. 一般调试方法

使用 Doom Emacs 时有经常查看、学习、掌握某些命令、函数的用法的需求,也因此需要对某个函数进行单步调试的方法或工作流。

  1. 在对应的函数上启动 +emacs-lisp/edebug-instrument-defun-on 以打开调试;
  2. M-x 执行目标调试函数或者在 ielm 执行需要调试的函数,以 edebug-mode 进入调试函数代码体并暂停;
  3. 如果在 evil-mode normal 模式,最好 C-z 以进入 emacs-mode
  4. 断点操作:光标跳到一个位置执行 b 会对光标最近的 S-expression1 做断点操作;
  5. 回归当前断点/where:执行 w 回到当前断点处,也就是程序当前停的地方;
  6. 浏览下一断点: B 跳到下一个断点,持续 B 在该轮 edebug-mode 的下一个断点进行跳转;
  7. continue 到下一断点: c 对应 edebug-continue-mode ,然后迅速按 S 对应 edebug-stop 停下来,否则会以秒速 step 的步调往后调试;
  8. emacs-mode 下,使用 SPC 来进行 step 操作,对应 edebug-step-mode
  9. 在对应的函数上启动 +emacs-lisp/edebug-instrument-defun-off 以取消调试;

2. 进入下一层栈时取消上层函数调试避免断点过多

有时候需要快速定位某问题也有一些另一些操作,以自己在使用 doom 的 +org/dwim-at-point 打开一个链接时报 Firefox crash report 错误为例。 ELisp 函数调用有调用栈,当执行快捷键时调用的一般是入口函数例如这里提到的 +org/dwim-at-point 。当需要深入到问题中时,实际上就是深入到 ELisp 的函数调用栈中。 下面是我调试的步骤,也作为后续调试的一个参考吧:

  1. 首先惯例使用 +emacs-lisp/edebug-instrument-defun-on 来调试入口函数 +org/dwim-at-point
  2. 按键触发函数断点停止于 +org/dwim-at-point 后,单步调试找出下一步会调用的函数(栈) (org-open-at-point arg) 。大多数情况下不能一眼看出来会进入这个函数,此时直接执行 edebug-stop (快捷键 S )以停止 edebug 并进行下一次按键复现以进入 org-open-at-point 栈中。当再一次按键触发复现时,可以在 edebug-mode 中移动光标到需要停住的 sexp 的前括号处,然后调用 edebug-goto-here (快捷键 H )会运行并停止到这里。
  3. 执行 edebug-instrument-callee (快捷键 I )以 instrument 函数 org-open-at-point 以备调试,同时取消掉上一栈的调试 edebug-remove-instrument 并在弹出的对话框中选择 +org/dwim-at-point ,避免后续复现时调试断点过多以集中注意力。