Chrome DevTools 调试 WASM 的完整指南Debugging WASM in Chrome DevTools
Chrome DevTools 内置强大的 WebAssembly 调试功能,支持源码映射、断点设置和内存检查。作者分享了在 Scheme 编译器生成 WASM 时遇到的调试挑战及解决方案,涵盖变量追踪、调用栈分析和性能优化技巧。
在为我的 Scheme 编译器开发 WASM 后端时,我在调试生成的 WASM 代码时遇到了几个棘手的情况。结果发现 Chrome 的 DevTools 中有一个功能非常强大的 WASM 调试器,因此在这篇简短的博文中,我想分享一下如何使用它。
设置和测试环境
本文将使用 wasm-wat-samples 项目中的一个示例。实际上,gc-print-scheme-pairs 示例已经完成了所有准备工作。该示例展示了如何在 WASM 中使用 GC 引用构造类似 Scheme 的 s-expr,并递归地打印它们。该示例支持嵌套整数、布尔值和符号对。
要查看其效果,我们必须先将 WAT 文件编译为 WASM,例如使用 watgo:
$ cd gc-print-scheme-pairs
$ watgo parse gc-print-scheme-pairs.wat -o gc-print-scheme-pairs.wasm该目录中的 browser-loader.html 文件已经期望加载 gc-print-scheme-pairs.wasm。但我们不能直接从文件系统打开它;由于它加载的是 WASM,因此需要通过本地 HTTP 服务器提供服务。我个人使用 static-server,但你也可以使用其他工具,比如 Python 内置的 http.server:
$ static-server
2026/04/10 08:55:20.244096 Serving directory "." on http://127.0.0.1:8080
...现在可以通过点击打印出的链接并选择 browser-loader.html 文件在浏览器中打开。
调试过程
打开 Chrome DevTools,在 Sources 面板中,左侧打开 Page 视图。它应该在 wasm 下有一个条目,显示我们模块的反编译 WAT 代码。注意:此代码是从二进制 WASM 反汇编而来,因此会丢失一些 WAT 语法糖(如折叠指令):
可以通过点击代码左侧地址列设置断点,然后刷新页面。DevTools 调试器将重新运行程序并在断点处停止:
在这里可以单步执行、进入函数、查看局部变量和调用栈等——真正的调试器!
调试意外异常
在开发编译器时,对我来说最重要的用例是调试意外的异常(来自 ref.cast 等指令)。注意上一张截图右侧的复选框“暂停于...异常”。选中这些选项后,DevTools 调试器会自动在异常处停止,并显示其来源。让我们修改 gc-print-scheme-pairs.wat 示例来演示这一点。$emit_value 函数在执行类型转换前会进行一组 ref.test 检查以确定引用的类型;让我们在最开始添加这一行:
(call $emit_bool (ref.cast (ref $Bool) (local.get $v)))显然,在没有先测试的情况下就假设 $v 是布尔引用是错误的;这仅用于演示目的。
不设置任何断点,用 watgo 重新编译此代码并重新加载页面,我们会得到:
调试器在导致异常的指令处停止;此外,在右侧的 Scope 面板中我们可以看到 $v 的实际类型是 (ref $Pair),因此问题一目了然。
我发现这种能力在编写或使用编译器生成涉及 GC 类型和指令的非平凡 WASM 代码片段时非常有价值。
WASM 中的调试器 vs. printf
“应该使用调试器还是仅仅使用 printf”是程序员之间常见的争论话题。虽然我通常属于“printf 调试”阵营,但我并不教条,当情况需要时,我肯定会选择调试器。
具体来说,在调查 WASM 中的引用异常时,有两个强有力的因素使得选择调试器成为更优解:
需要完整排版与评论请前往来源站点阅读。