Skip to content

Proposal: cross-platform source-level debugging for native, embedded, WASI, and browser WebAssembly #2164

Description

@cpunion

Summary

Provide source debugging across native, embedded, browser and WASI targets using shared DWARF/artifact identity and a versioned runtime schema, with target-specific execution control.

Updated 2026-10-06 against main f167e3c6d9ae1bff971669180753a223fe437461. The first-stage integration is merged. This umbrella remains open for the software capabilities below; physical-board/probe qualification is deferred because no device is currently available. The focused native LLDB scope is tracked in #2154.

Architecture and compatibility contracts

Keep three layers distinct:

  1. Compiler and artifacts: valid DWARF locations/scopes/types, executable identity, optional external DWARF, and independent runtime pclntab data.
  2. Execution control: native LLDB/GDB, embedded remote probes/emulators, browser DevTools, or a runtime's supported Wasm guest-debug protocol.
  3. Runtime presentation: versioned adapters for LLGo strings, slices, interfaces, functions, closures, maps, channels and supported goroutine/thread views.

Native compile units retain DW_LANG_C for stock-debugger interoperability and DW_AT_producer = LLGo. This does not introduce a Go-language LLDB fork or a general Go expression evaluator. The canonical debugger schema and native/Wasm records identify target size, byte order, ABI and runtime-layout versions. Unsupported records disable LLGo presentation with a clear explanation while preserving ordinary raw debugging.

Port the schema to the current single C ABI and runtime layouts. Removed none/cfunc/allfunc modes and the old module path must not become new compatibility obligations. Share schema and fixtures across LLDB/GDB/browser consumers; do not force them to share implementation language or private APIs.

Debug artifacts and defaults

Native macOS, Linux and Windows builds follow the platform toolchain's default DWARF packaging. Retention policy (-w) is separate from physical placement: this proposal does not require native DWARF embedding, extraction, standalone dSYM/debug-file generation, or an additional packaging acceptance gate. Explicit embedded/external packaging applies to Wasm; embedded devices retain the host debug ELF and separate deployment image. These rules follow the target, independently of the build-host OS.

Mode Contract
embedded Retain DWARF in the Wasm module; native use only requests preservation with platform-default packaging
external Publish a debugger-owned Wasm sidecar paired with the deployed module
host Retain the linked debug ELF on the host and derive separate flash/deployment bytes
none Omit DWARF according to the typed build policy

The intended flag is -debug-artifact=embedded|external|host|none. Unsupported target/mode combinations must fail explicitly. Keep this separate from pclntab's runtime loading and packaging: external DWARF is read by a debugger, not by the running LLGo program.

Go -w controls DWARF, and -s implies -w unless explicitly overridden by -w=false. The native default-DWARF correction belongs to #2142. This consolidation does not turn ordinary Wasm/embedded production builds into debug builds. llgo debug explicitly requests retained debug information and defaults to O0 unless the user selects another supported optimization level.

Embedded debug sections remain host-side non-loadable data. Producing a debug ELF must not alter the corresponding flashed .bin/.hex/.uf2 bytes. Artifact reporting distinguishes executable, debug, deployment and runtime-symbolization roles and reports actual file sizes.

For Wasm, publish external DWARF with standard external_debug_info, verified module identity, URL-safe paths and atomic publication/cleanup. Validate the final artifact after all post-link transformations. Use the supported patched Binaryen build baseline from #2632/#2652; do not reintroduce a temporary, separate Binaryen pin or treat the already-fixed Asyncify DWARF issue as a new prerequisite.

Implemented in main

Capability Delivery Status / boundary
Native DWARF correctness, defaults and source locations #2142 Merged; platform-default native DWARF packaging
Common debugger schema and LLDB/GDB runtime views #2712 Merged; shared fixtures and explicit unsupported-platform behavior
llgo debug, Wasm embedded/external DWARF, embedded remote/load/reset #2269 Merged; real QEMU transport and image download/reset acceptance
Browser source breakpoints, paused locals, artifact/source identity #2713 Merged; real Chrome Memory32/64 acceptance

Native acceptance remains platform-specific: LLDB is the native choice on macOS arm64; GDB supports embedded remote sessions there. Stock GDB's blocked-worker unwind is limited on Intel macOS and Windows ARM64, while the narrower values/registry/main-stack acceptance is covered. Linux and Windows x64/x86 retain strict complete-worker acceptance. Broader MCU architectures and physical probes require their own qualification; QEMU results do not establish hardware coverage.

Remaining software work

Task Implementation / acceptance required Progress
Browser logical G/source stacks Live ID/parent/state/last-P registry, parked fiber function/file/line stacks, GC and exit cleanup; opt-in overhead and cache separation #2742 submitted and rebased onto current main; local Memory32/64, 1/2/4-worker and embedded/external DWARF acceptance passes. Compiler/debug command/ABI units and all 24 extension tests pass on the latest base. Previous-head browser/Wasmtime/Wasmer checks pass and review comments are addressed; current Wasm/browser/runtime and patch-coverage checks pass at ede69416e4e7648a36189f578d4f1c69ed68ce05; host checks remain running/queued
Browser coordinated worker control Pause/resume every relevant worker, manage worker lifecycle and stable stop IDs, then inspect shared memory consistently The #2742 acceptance pauses all worker targets through Chrome's real debugger transport. Product users still pause other threads in DevTools; automatic coordination is not implemented
Parked-frame variables and complete runtime views Recover selected logical-frame locals where the runtime/compiler can expose them; finish deep runtime-object inspection with GC/memory-growth/optimized-out cases Still pending; logical function/file/line stacks alone do not satisfy this gate
W32 WASI interactive debugging Real guest source breakpoints/stepping/locals, thread control and shared-memory/runtime views; preserve shared env.memory, wasi.thread-spawn, real thread exit and EH Still pending. Execution currently uses Wasmer; llgo debug -target=wasi correctly rejects the incompatible Wasmtime path
Maintained qualification record Record exact compiler/runtime/debugger/browser versions and tested configurations, source identity and deployment/debug sizes Each implementation carries its evidence; expand as the remaining adapters become available

WASI engine selection must follow actual debugger capabilities. Wasmer's experimental artifact profiler can produce native source maps, but its current generated debugger DWARF covers functions/lines, not the complete guest-variable/shared-memory contract. WAMR's interpreter debugger documentation explicitly excludes pthread/thread-spawn debugging. Neither substitutes for current W32 pthread/EH acceptance. Do not introduce single-thread artifacts, synthetic imports or disabled EH to make a debugger test pass.

Acceptance and hardware

  • Integrate the four first-stage contributions into main.
  • Preserve native platform defaults and typed Wasm/embedded artifact contracts.
  • Execute native LLDB/GDB and embedded QEMU transports against real binaries.
  • Execute browser source/local-variable sessions with actual Emscripten hosts.
  • Merge and qualify logical Wasm G/source stacks (debug: inspect parked Wasm goroutine source stacks #2742).
  • Deliver automatic browser worker control, parked-frame locals and complete runtime views.
  • Deliver a compatible W32 WASI guest-debugger transport and its real thread/EH/shared-memory acceptance.
  • Physical-board/probe qualification: deferred until hardware is available; retain download/reset, source/value and device/tool/version evidence.

Standalone acceptance is under test/debug/{native,runtime,embedded,hardware,wasm}; package-private tests remain beside their implementation. #2742 adds a separately tested browser decoder and real parked-stack/GC/exit checks, using Chrome for Testing 152 and patched Binaryen llgo-v132.3. A local integration of #2738/#2743/#2742 also passes all ten Chrome Memory32/64 sessions, including 1/2/4 workers and embedded/external DWARF. Sequence guards detect changes during inspection; they do not provide a globally simultaneous snapshot while other workers run. Logical-stack inspection does not imply parked-frame local-variable evaluation.

Compact nil-store panic metadata (#2406) and size optimization (#2679) remain separate workstreams. The proposal is not complete merely because its first-stage PRs merged.

Activity

  1. added
    wasmWebAssembly, wasm32, and WASI support
    embedSupport embed platform
    on Jul 23, 2026
  2. added theissue type on Jul 23, 2026
  3. added this to the LLGo v1.1 milestone on Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions