在 Chrome DevTools 中调试 WASM
当我为我的 Scheme 编译器开发 WASM 后端时,我在调试生成的 WASM 代码时遇到了一些棘手的情况。事实证明,Chrome 的 DevTools 中有一个非常强大的 WASM 调试器,因此在这篇简短的文章中我想分享一下如何使用它。
设置和线束
在这篇文章中,我将使用我的 wasm-wat-samples 项目中的一个示例。事实上,gc-print-scheme-pairs 示例中的所有内容都已经就位。此示例展示了如何使用 gc 引用在 WASM 中构造类似方案的 s-exprs 并递归地打印它们。该示例支持嵌套的整数、布尔值和符号对。
要查看实际效果,我们必须首先将 WAT 文件编译为 WASM,例如使用 watgo:
$ cd gc-print-scheme-pairs
$ watgo parse gc-print-scheme-pairs.wat -o gc-print-scheme-pairs.wasm
这 浏览器加载程序.html 该目录中的文件已预期加载
gc-print-scheme-pairs.wasm。但我们不能直接从文件系统打开它;由于它加载 WASM,因此该文件需要由本地 HTTP 服务器提供服务。我个人使用 static-server 来实现此目的,但你可以使用其他任何东西 – 比如 Python 的内置服务器 http服务器:
$ static-server
2026/04/10 08:55:20.244096 Serving directory "." on http://127.0.0.1:8080
...
现在可以通过点击打印的链接并选择在浏览器中打开它 浏览器加载程序.html 文件。
调试过程
打开 Chrome 开发工具,然后在 来源,打开 页 左侧视图。它应该有一个条目 瓦斯姆,这将显示我们模块的反编译 WAT 代码。注意:此代码是从二进制 WASM 反汇编的,因此它会丢失一些 WAT 语法糖(如折叠指令):

您可以通过点击代码左侧的地址栏来设置断点,然后刷新页面。 DevTools 调试器将再次运行程序并在断点处停止:

在这里您可以单步执行、进入、查看本地值和调用堆栈等 – 一个真正的调试器!
调试意外异常
在开发编译器时对我来说最重要的用例是调试意外异常(来自诸如 参考投射)。请注意上一个屏幕截图右侧的复选框,其中显示“在…异常时暂停”。选择这些后,DevTools 调试器将在出现异常时自动停止并显示异常的来源。我们来修改一下 gc-打印-方案对.wat 示例以查看其实际效果。这
$emit_value 函数执行一组 参考测试 在转换之前检查它正在处理哪种类型的引用;让我们在最开始添加这一行:
(call $emit_bool (ref.cast (ref $Bool) (local.get $v)))
显然这是错误的假设 $v 是一个 bool 引用,无需先对其进行测试;这仅用于演示目的。
不设置任何断点,重新编译此代码 沃特戈 并重新加载页面,我们得到:

调试器停在导致异常的指令处;此外,在
范围 在右侧窗格中我们可以看到实际类型 $v 是
(参考 $Pair),所以立即清楚发生了什么。
我发现在使用 gc 类型和指令编写(或从编译器发出)重要的 WASM 代码块时,此功能非常有价值。
wasm 中的调试器与 printfs
“我应该使用调试器还是只使用 printfs”是程序员之间争论的一个常见话题。虽然我通常属于“printf 调试”阵营,但我并不教条,并且在情况需要时肯定会使用调试器。
具体来说,在调查 WASM 中的引用异常时,有两个重要因素会导致决定使用调试器:
-
总的来说,WASM 的 printf 功能不是很好。我们可以从主机导入类似打印的函数(事实上,我们的示例就是这样做的),但它们不是很灵活,并且在 WASM 中处理字符串通常很痛苦。当使用 gc 类型时,情况会更加复杂,因为这些类型甚至对主机不可见(它们是不透明的引用)。如果我们想要对 gc 值进行 printf 调试,我们必须构建 很多 首先是脚手架。
-
一般来说,有了支持性的调试器,异常调试会容易得多。我们的 参考投射 上面的例子可能会发生异常 任何地方 在代码中。想象一下,必须调试一个非常大的 WASM 程序(由编译器发出)才能找到失败的根源
参考投射;调试器将带您到达现场!事实上,即使对于 C 编程,我也总是发现 数据库 对于查明分段错误和类似崩溃的根源最有用。
