- 语言运行时
- 嵌入式
- 物联网
【免费下载链接】wasm-micro-runtime
WebAssembly Micro Runtime (WAMR)
WAMR(WebAssembly Micro Runtime)提供了基于 DWARF 调试信息的源码级(source-level)调试能力,支持lldb作为前端调试器,可同时覆盖解释器与 AOT 两种执行模式。本文以 doc/source_debugging.md 为主线,结合 doc/source_debugging_interpreter.md、doc/source_debugging_aot.md 及仓库源码,完整讲解从"编译带调试信息的 wasm 应用"到"构建定制 lldb、连接 iwasm 断点调试"的端到端流程,并给出嵌入式场景下通过wasm_runtime_start_debug_instance启用调试的 API 用法,帮助你快速定位 C/C++/Rust wasm 应用中的源码级问题。
一、前置条件:让 wasm 应用携带 DWARF 调试信息
源码级调试的前提是 wasm 二进制中嵌入 DWARF 调试段。使用-g选项编译即可,适用于 wasi-sdk(同样适用于 emcc 与 rustc):
/opt/wasi-sdk/bin/clang -g test.c -o test.wasm编译完成后得到带 DWARF 段的test.wasm。可以用llvm-dwarfdump验证调试信息是否真正嵌入:
llvm-dwarfdump-12 test.wasm说明:WAMR 的源码调试基于 DWARF(通常用于 C/C++/Rust);AssemblyScript 常用的 source map 调试信息不支持。
二、解释器模式源码调试(Interpreter)
1. 安装依赖库
apt update && apt install cmake make g++ libxml2-dev -y2. 构建带调试功能的 iwasm
进入 linux 平台目录并开启WAMR_BUILD_DEBUG_INTERP编译开关:
cd ${WAMR_ROOT}/product-mini/platforms/linux mkdir build && cd build cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 make注意:在 macOS M1 环境下,需额外传入
-DWAMR_DISABLE_HW_BOUND_CHECK=1配置项。
该开关对应的底层宏为WASM_ENABLE_DEBUG_INTERP,它在 debug-engine 库 与 product-mini/platforms/posix/main.c 等多处被条件编译使用,只有开启后-g=启动参数和wasm_runtime_start_debug_instanceAPI 才可用。
3. 以调试引擎启动 iwasm
iwasm -g=127.0.0.1:1234 test.wasm # 端口设为 0 时,由系统随机分配调试端口从 posix/main.c 的源码可以看到-g=参数的解析逻辑:-g=ip:port会被拆分为 IP 地址与端口号,写入运行时的调试配置;格式不正确时直接打印帮助信息。也就是说,调试服务器(gdbserver)内嵌在 iwasm 进程中,监听指定地址等待 lldb 连接。
4. 构建定制化 lldb
WAMR 的 lldb 调试能力基于 LLVM 补丁(WasmProcess),需要构建带 wasm 支持的自定义 lldb:
git clone --branch release/13.x --depth=1 https://github.com/llvm/llvm-project cd llvm-project git apply ${WAMR_ROOT}/build-scripts/lldb_wasm.patch mkdir build-lldb cmake -S ./llvm -B build-lldb \ -G Ninja \ -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" \ -DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \ -DLLVM_BUILD_DOCS:BOOL=OFF -DLLVM_BUILD_EXAMPLES:BOOL=OFF \ -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF -DLLVM_BUILD_TESTS:BOOL=OFF \ -DLLVM_ENABLE_BINDINGS:BOOL=OFF -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ -DLLVM_INCLUDE_DOCS:BOOL=OFF -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ -DLLVM_INCLUDE_TESTS:BOOL=OFF -DLLVM_ENABLE_LIBXML2:BOOL=ON cmake --build build-lldb --target lldb --parallel $(nproc) # 生成的 lldb 位于 build-lldb/bin/lldb注意:macOS 若使用 CommandLineTools,需确保
/Library/Developer/CommandLineTools/SDKs下仅存在一个 SDK。也可以直接从官方 release 页下载预编译的
wamr-lldb二进制,避免本地构建。仓库的 CI 工作流 build_wamr_lldb.yml 即演示了完整构建与验证流程。
补丁文件位于仓库 build-scripts/lldb_wasm.patch,它引入了wasm调试平台协议,使 lldb 能与 iwasm 内置的 gdbserver 通信。
5. 启动 lldb 并连接 iwasm
lldb (lldb) process connect -p wasm connect://127.0.0.1:1234连接成功后,即可使用 lldb 的标准命令(breakpoint、next、step、print等)对 wasm 应用进行源码级调试,命令用法可参考 lldb 官方教程。
若 lldb 运行在非 Linux 平台,请在连接前先执行
platform select remote-linux:(lldb) platform select remote-linux (lldb) process connect -p wasm connect://127.0.0.1:1234
三、在嵌入式程序中启用解释器调试
如果你不是使用 iwasm 命令行工具,而是将 WAMR 嵌入到自有程序中,需要通过三步启用调试:
1. 初始化运行时环境时设置调试参数
RuntimeInitArgs init_args; memset(&init_args, 0, sizeof(RuntimeInitArgs)); /* ... */ strcpy(init_args.ip_addr, "127.0.0.1"); init_args.instance_port = 1234; /* * 或将端口设为 0,由操作系统分配端口 * init_args.instance_port = 0; */ if (!wasm_runtime_full_init(&init_args)) { return false; }这两个字段定义在 core/iwasm/include/wasm_export.h 的RuntimeInitArgs中:ip_addr[128]为调试服务器监听地址,instance_port为监听端口,注释明确指出它们仅在WASM_ENABLE_DEBUG_INTERP != 0时生效。
2. 创建调试实例
/* 初始化、加载与实例化 ... */ exec_env = wasm_runtime_create_exec_env(module_inst, stack_size); uint32_t debug_port = wasm_runtime_start_debug_instance(exec_env);wasm_runtime_start_debug_instance返回实际调试端口。查看其实现 wasm_runtime_common.c 可以确认两点:
- 它要求
WASM_ENABLE_THREAD_MGR与WASM_ENABLE_DEBUG_INTERP同时开启; - 若传入的是 AOT 模块,会输出 "Attempt to create a debug instance for an AOT module" 警告并返回 0——该 API 仅服务于解释器模式;
- 它内部转发给
wasm_runtime_start_debug_instance_with_port(exec_env, -1),即端口为 -1 时交由系统分配;也可以通过带port参数的变体显式指定端口。
3. 构建时开启调试特性
cmake .. -DWAMR_BUILD_DEBUG_INTERP=1或者直接在 cmake 文件中设置:
set (WAMR_BUILD_DEBUG_INTERP 1)使用注意事项
- 多线程 wasm 模块不支持调试:如果 wasm 模块使用 pthread API(见 doc/pthread_library.md),或嵌入器通过
wasm_runtime_spawn_thread创建新的 wasm 线程,调试时可能出现意外行为。注意这里指的是"wasm 线程"而非原生线程——在多个不同原生线程中执行 wasm 函数不会影响调试功能正常运行。 - 同一 module 不要创建多个 instance:调试器会修改(设置/清除断点)
wasm_module的字节码,因此多个实例共享同一 module 会导致异常。若确实需要从同一字节码得到多个实例,应先将字节码复制到新的缓冲区,再加载新的wasm_module并实例化。
四、AOT 模式源码调试(Experimental)
注意:AOT 调试目前处于实验阶段,仅支持少量调试能力。
1. 构建带调试支持的 lldb
假设你已经构建过 LLVM(位于${WAMR_ROOT}/core/deps/llvm/build):
cd ${WAMR_ROOT}/core/deps/llvm/build cmake ../llvm -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLDB_INCLUDE_TESTS=OFF make -j $(nproc)2. 构建带调试特性的 wamrc
cd ${WAMR_ROOT}/wamr-compiler mkdir build && cd build cmake .. -DWAMR_BUILD_DEBUG_AOT=1 make -j $(nproc)3. 构建带调试特性的 iwasm
cd ${WAMR_ROOT}/product-mini/platforms/linux mkdir build && cd build cmake .. -DWAMR_BUILD_DEBUG_AOT=1 make4. 将 wasm 模块编译为 AOT 模块
wamrc -o test.aot test.wasm5. 用 lldb 启动 iwasm 进行调试
与解释器模式"lldb 远程连接 iwasm"不同,AOT 调试是在当前终端里直接用 lldb 启动 iwasm,同时调试 WAMR 运行时本身与 wasm 应用:
% lldb iwasm -- test.aot (lldb) target create "iwasm" Current executable set to 'iwasm' (x86_64). (lldb) settings set -- target.run-args "test.aot" (lldb) settings set plugin.jit-loader.gdb.enable on (lldb) b main Breakpoint 1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020 (lldb) run Process 27954 launched: '/tmp/bin/iwasm' (x86_64) Process 27954 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100001020 iwasm`main(argc=2, argv=0x00007ff7bfeff678) at main.c:294:11 291 int 292 main(int argc, char *argv[]) 293 { -> 294 int32 ret = -1; 295 char *wasm_file = NULL; 296 const char *func_name = NULL; 297 uint8 *wasm_file_buf = NULL; Target 0: (iwasm) stopped. (lldb) c Process 27954 resuming 1 location added to breakpoint 1 error: need to add support for DW_TAG_base_type 'void' encoded with DW_ATE = 0x0, bit_size = 0 Process 27954 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2 frame #0: 0x00000001002980a0 JIT(0x100298004)`main(exenv=0x0000000301808200) at hello.c:6:9 3 int 4 main(void) 5 { -> 6 printf("hello\n"); 7 8 return 0; 9 } Target 0: (iwasm) stopped. (lldb) br l Current breakpoints: 1: name = 'main', locations = 2, resolved = 2, hit count = 2 1.1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020, resolved, hit count = 1 1.2: where = JIT(0x100298004)`main + 12 at hello.c:6:9, address = 0x00000001002980a0, resolved, hit count = 1 (lldb)在上述示例中需要注意:
- 第一个
main(位于main.c)是iwasm 命令自身的入口函数; - 第二个
main(位于hello.c)是AOT 编译后 wasm 模块的入口函数; - 一个断点命中了两处:先停在本机可执行文件的
main,再停在被调试模块 JIT 代码中的main。
关键机制——GDB JIT loader:WAMR AOT 调试借助 GDB JIT loader 机制加载被调试模块的调试信息。在 macOS 等部分平台上需要显式开启:
(lldb) settings set plugin.jit-loader.gdb.enable on五、调试引擎在仓库中的实现脉络
解释器调试所依赖的内置调试服务器位于 core/iwasm/libraries/debug-engine,其核心文件包括:
- gdbserver.c:调试服务器主体,维护控制线程并监听调试端口;
- packets.c:解析 GDB 远程调试协议数据包(含断点设置、读写内存等);
- handler.c:处理具体的调试请求(寄存器、内存、单步等);
- utils.c:调试辅助工具函数。
整个调用链可概括为:iwasm 启动时通过-g=ip:port(posix/main.c)或嵌入器通过RuntimeInitArgs配置监听地址 →wasm_runtime_start_debug_instance创建调试实例(wasm_runtime_common.c)→ debug-engine 在指定端口提供 gdbserver 服务 → 定制 lldb 通过process connect -p wasm接入,借助 DWARF 信息将字节码地址映射回源码行号,实现断点、单步、变量查看等能力。
此外,仓库 CI 中已有大量回归验证:例如 compilation_on_ubuntu.yml 与 compilation_on_android.yml 均以-DWAMR_BUILD_DEBUG_AOT=1、-DWAMR_BUILD_DEBUG_INTERP=1组合进行编译验证,nightly_run.yml 也在常规构建中开启两个调试特性,可作为"开关与组合方式正确性"的参考。
六、两种调试模式对比小结
| 维度 | 解释器调试 | AOT 调试 |
|---|---|---|
| 编译开关 | -DWAMR_BUILD_DEBUG_INTERP=1 | -DWAMR_BUILD_DEBUG_AOT=1(wamrc 与 iwasm 都要开启) |
| 调试信息载体 | wasm 模块内嵌 DWARF | AOT 模块的 JIT 调试信息 |
| 连接方式 | lldb远程连接 iwasm(process connect -p wasm) | lldb iwasm -- test.aot本地启动 |
| 关键机制 | iwasm 内置 gdbserver(debug-engine 库) | GDB JIT loader(需在部分平台显式开启) |
| 稳定性 | 成熟可用 | 实验阶段,仅少量调试能力 |
| 注意事项 | 不支持多线程 wasm 模块;同一 module 勿多实例化 | 断点可能同时命中运行时与 wasm 应用的同名函数 |
小结:解释器模式适合日常开发与调试,AOT 模式适合在验证 AOT 生成代码行为时使用。无论哪种方式,都要求 wasm 应用以-g编译并携带 DWARF 信息,且需要配套的定制 lldb。掌握这两套流程后,你就可以在 WAMR 上获得与原生开发接近的源码级调试体验。
- 语言运行时
- 嵌入式
- 物联网
【免费下载链接】wasm-micro-runtime
WebAssembly Micro Runtime (WAMR)
相关推荐
WAMR 源码级调试完全指南:基于 DWARF 的 WebAssembly 应用调试(解释器与 AOT)
WAMR 源码级调试完全指南:基于 DWARF 的 WebAssembly 应用调试(解释器与 AOT) WAMR(WebAssembly Micro Runt
可观测性日志分析云原生流处理WAMR 解释器源码级调试实战:基于 DWARF 与 lldb 的 wasm 应用调试全指南
WAMR 解释器源码级调试实战:基于 DWARF 与 lldb 的 wasm 应用调试全指南 本篇技术指南以 wasm micro runtime(WAMR)官
可观测性日志分析云原生流处理WAMR AOT 源码级调试指南:基于 lldb 与 GDB JIT Loader 的完整实战流程
WAMR AOT 源码级调试指南:基于 lldb 与 GDB JIT Loader 的完整实战流程 WAMR(WebAssembly Micro Runtime
可观测性日志分析云原生流处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考