调试器 API¶
Debugger 接口¶
Mozilla 的 JavaScript 引擎 SpiderMonkey 提供了一个名为 Debugger
的调试接口,它允许 JavaScript 代码观察和操纵其他 JavaScript 代码的执行。Firefox 的内置开发者工具和 Firebug 扩展程序都使用 Debugger
来实现其 JavaScript 调试器。但是,Debugger
非常通用,可用于实现其他类型的工具,例如跟踪器、覆盖率分析、修补和继续等等。
Debugger
具有三个基本特性
它是一个源代码级别的接口:它根据 JavaScript 语言进行操作,而不是机器语言。它对 JavaScript 对象、堆栈帧、环境和代码进行操作,并提供一致的接口,无论被调试者是解释执行、编译执行还是优化执行。如果您精通 JavaScript 语言,那么您应该具备使用
Debugger
所需的所有背景知识,即使您从未深入了解过该语言的实现。它供JavaScript 代码使用。JavaScript 既是被调试语言,也是工具实现语言,因此使 JavaScript 在 Web 上有效的特性可以用于为开发人员创建工具。正如预期的那样,JavaScript API
Debugger
是一个健全的接口:使用(甚至滥用)Debugger
绝不应该导致 Gecko 崩溃。错误会抛出正确的 JavaScript 异常。它是一个线程内调试 API。被调试者和使用
Debugger
观察它的代码必须在同一个线程中运行。跨线程、跨进程和跨设备工具必须使用Debugger
从同一线程内观察被调试者,然后自行处理任何必要的通信。(Firefox 的内置工具为此目的定义了一个协议)。
在 Gecko 中,Debugger
API 仅对 chrome 代码可用。根据设计,它不应该引入安全漏洞,因此原则上它也可以提供给内容;但很难证明增加攻击面的安全风险是合理的。
Debugger
API 目前无法观察自托管 JavaScript。这不是 API 设计固有的,而是自托管基础设施尚未准备好应对 Debugger
API 可以执行的入侵。
调试器实例和影子对象¶
Debugger
将被调试者状态的各个方面反映为 JavaScript 值——不仅是实际的 JavaScript 值(如对象和基本类型),还包括堆栈帧、环境、脚本和编译单元,这些通常不能作为它们本身的对象访问。
以下是一个正在运行计时器回调函数的 JavaScript 程序
正在运行的 JavaScript 程序及其调试器影子
此图显示了构成调试器 API 的各种类型的影子对象(它们都遵循一些通用约定)
一个Debugger.Object 表示一个被调试者对象,提供一个面向反射的 API,防止调试器意外调用 getter、setter、代理陷阱等等。
一个Debugger.Script 表示一个 JavaScript 代码块——函数体或顶级脚本。给定一个
Debugger.Script
,可以设置断点,在源代码位置和字节码偏移量之间转换(偏离“源代码级别”设计原则),并找到代码的其他静态特性。一个Debugger.Frame 表示一个正在运行的堆栈帧。您可以使用它们遍历堆栈并找到每个帧的脚本和环境。您还可以为帧设置
onStep
和onPop
处理程序。一个Debugger.Environment 表示一个环境,将变量名与存储位置关联起来。环境可能属于一个正在运行的堆栈帧、被函数闭包捕获,或者将某个全局对象的属性反映为变量。
Debugger 实例本身并不是被调试者中任何内容的影子;相反,它维护着一组要被视为被调试者的全局对象。一个 Debugger
仅观察在这些全局对象的范围内发生的执行。您可以设置函数,在推送新的堆栈帧时调用;在加载新代码时调用;等等。
此图中省略了 Debugger.Source 实例,它们表示 JavaScript 编译单元。一个 Debugger.Source
可以提供其源代码的完整副本,并解释代码如何进入系统,无论是通过对 eval
的调用、<script>
元素还是其他方式。一个 Debugger.Script
指向其派生的 Debugger.Source
。
还省略了 Debugger
的 Debugger.Memory 实例,它包含用于观察被调试者内存使用情况的方法和访问器。
所有这些类型都遵循一些通用约定,在深入研究任何特定类型的规范之前,您应该先浏览这些约定。
所有影子对象对于每个 Debugger
和每个引用都是唯一的。对于给定的 Debugger
,只有一个 Debugger.Object
引用特定的被调试者对象;对于特定的堆栈帧,只有一个 Debugger.Frame
;等等。因此,工具可以将关于影子的引用的元数据存储为影子本身上的属性,并在再次遇到相同的引用时找到该元数据。并且由于影子是每个 Debugger
的,因此工具可以这样做而无需担心干扰使用自己 Debugger
实例的其他工具。
示例¶
以下是一些您可以自己尝试的事情,它们展示了 Debugger
的一些功能
设置断点 在页面中,在断点命中时运行一个处理程序函数,该函数在页面的上下文中计算表达式。
Gecko 特定功能¶
虽然 Debugger
核心 API 仅处理任何 JavaScript 实现通用的概念,但它也包含一些 Gecko 特定的功能
[全局跟踪][global] 支持一次调试 Gecko 实例中运行的所有代码——“chrome 调试”模型。
[对象包装器][wrapper] 函数有助于操作跨越权限边界的对象引用。
源代码元数据¶
- 从文件生成
js/src/doc/Debugger/Debugger-API.md
- 水印
sha256:6ee2381145a0d2e53d2f798f3f682e82dd7ab0caa0ac4dd5e56601c2e49913a7
- 变更集