19.1.11 调试器的内部实现

本节介绍调试器内部使用的函数和变量。

Variable: debugger

该变量的值是用于调用调试器的函数。 其值必须是接受任意数量参数的函数,或更常见的是函数名。 该函数应触发某种调试器。变量的默认值为 debug

Lisp 传递给该函数的第一个参数表示调用原因。 参数的约定在 debug 的说明中有详细描述(see 调用调试器)。

Function: backtrace

该函数打印当前活跃的 Lisp 函数调用跟踪信息。 输出的跟踪信息与 debug*Backtrace* 缓冲区中显示的内容完全相同。 函数的返回值始终为 nil

以下示例中,Lisp 表达式显式调用 backtrace。 这会将调用栈打印到流 standard-output, 本示例中该流对应缓冲区 ‘backtrace-output’。

调用栈的每一行代表一次函数调用。 如果函数的所有参数值均已确定,该行会显示函数名及参数值列表; 如果参数仍在计算中,该行则显示包含函数及其未求值参数的列表。 长列表或深度嵌套的结构可能会被省略。

(with-output-to-temp-buffer "backtrace-output"
  (let ((var 1))
    (save-excursion
      (setq var (eval '(progn
                         (1+ var)
                         (list 'testing (backtrace))))))))

     ⇒ (testing nil)

----------- Buffer: backtrace-output ------------
  backtrace()
  (list 'testing (backtrace))
  (progn ...)
  eval((progn (1+ var) (list 'testing (backtrace))))
  (setq ...)
  (save-excursion ...)
  (let ...)
  (with-output-to-temp-buffer ...)
  eval((with-output-to-temp-buffer ...))
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp)
----------- Buffer: backtrace-output ------------
User Option: debugger-stack-frame-as-list

若该变量为非nil,调用栈中的每个栈帧都会以列表形式显示。 此举旨在提升调用栈的可读性,但代价是特殊形式与常规函数调用在视觉上不再有区别。

debugger-stack-frame-as-list 为非nil 时,上述示例的输出如下:

----------- Buffer: backtrace-output ------------
  (backtrace)
  (list 'testing (backtrace))
  (progn ...)
  (eval (progn (1+ var) (list 'testing (backtrace))))
  (setq ...)
  (save-excursion ...)
  (let ...)
  (with-output-to-temp-buffer ...)
  (eval (with-output-to-temp-buffer ...))
  (eval-last-sexp-1 nil)
  (eval-last-sexp nil)
  (call-interactively eval-last-sexp)
----------- Buffer: backtrace-output ------------
Variable: debug-on-next-call

若该变量为非nil,表示在下一次调用 evalapplyfuncall 前调用调试器。 进入调试器后,该变量 debug-on-next-call 会被设为 nil

调试器中的 d 命令正是通过设置该变量实现功能。

Function: backtrace-debug level flag

该函数设置调用栈中向下数 level 层的栈帧的“退出时调试”标志,将其值设为 flag。 若 flag 为非nil,该栈帧后续退出时会触发调试器。 即使通过该栈帧进行非本地退出,也会进入调试器。

该函数仅由调试器内部使用。

Variable: command-debug-status

该变量记录当前交互式命令的调试状态。 每次交互式调用命令时,该变量会被绑定为 nil。 调试器可设置该变量,为同一命令调用期间后续的调试器触发留存信息。

使用该变量而非普通全局变量的优势在于: 其数据不会延续到后续的命令调用中。

该变量已废弃,将在未来版本中移除。

Function: backtrace-frame frame-number &optional base

函数 backtrace-frame 专为 Lisp 调试器设计使用。 它返回调用栈中向下数 frame-number 层的栈帧的计算状态信息。

如果该栈帧尚未求参数值,或属于特殊形式,返回值为 (nil function arg-forms…)

如果该栈帧已完成参数求值并调用了函数,返回值为 (t function arg-values…)

返回值中,function 是被求值列表的 CAR 部分, 若是宏调用则为 lambda 表达式。 如果函数包含 &rest 参数,该参数会表示为 arg-values 列表的尾部。

若指定了 base,则 frame-number 相对于 functionbase 的最顶层栈帧计数。

frame-number 超出范围,backtrace-frame 返回 nil

Function: mapbacktrace function &optional base

函数 mapbacktrace 会为调用栈中的每个栈帧调用一次 function, 起始位置为 function 等于 base 的第一个栈帧 (若省略 base 或其值为 nil,则从栈顶开始)。

调用 function 时传入四个参数:evaldfuncargsflags

如果栈帧尚未求参数值或属于特殊形式,evaldnilargs 为表达式列表。

如果栈帧已完成参数求值并调用了函数,evaldtargs 为值列表。 flags 是当前栈帧属性的属性列表(plist): 目前仅支持 :debug-on-exit 属性, 若栈帧的“退出时调试”标志已设置,则该属性值为 t


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike