Skip to content

Debugging: Keep a component's breakpoints in the module they were set in - #15194

Open
sansmoraxz wants to merge 1 commit into
bytecodealliance:mainfrom
sansmoraxz:guest_debug_single_step_by_module
Open

sansmoraxz wants to merge 1 commit into
bytecodealliance:mainfrom
sansmoraxz:guest_debug_single_step_by_module

Conversation

@sansmoraxz

@sansmoraxz sansmoraxz commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #15182. A component's core modules share one code image and one frame table, and the frame table told breakpoint sites apart only by their module-relative Wasm PC, so the same PC in two modules was taken for the same site. There are two fixes, one per commit.

Keep inlined breakpoints when single-stepping ends. Since #15182, each module re-patches only the sites in its own range of the code. But with inlining, a function from one module can be inlined into a caller from another. Its sites are then in the caller's range, and were re-patched by the caller's module, so a breakpoint in the inlined function was lost. The frame table now records each site's module (the innermost frame's, so inlined code keeps its own), and re-patching goes by that. This removes the text-range accessors added in #15182: where a site is in the code says whose function it is in, not whose Wasm code it is, and once the frame table records the module the range isn't needed. Re-patching also gets cheaper: it walks only the module's own sites, found by a binary search.

Scope breakpoint lookups to one module. Adding, removing and slipping a breakpoint looked its sites up by PC alone, across all modules. So:

  • a breakpoint set in one module also stopped another module at the same PC,
  • removing one module's breakpoint also removed another module's at the same PC,
  • a breakpoint past the last site of its module slipped to a site in another module.

The sites are now sorted by module, then PC, and each lookup is scoped to one module. FrameTable::breakpoint_patches now takes a module, and objdump uses the new all_breakpoint_patches.

Tests:

  • component_inlined_breakpoint_survives_single_step sets a breakpoint in a function called from another module, with inlining off and on.
  • component_breakpoint_stays_in_its_module and component_breakpoint_slips_within_its_module without it, a breakpoint in one module also stops the other, and a breakpoint past module 0's code lands in module 1. TWO_MODULES now has both functions at the same PCs; the old one, with padding, is TWO_MODULES_PADDED.

Single-stepping off re-patches each module's breakpoint sites by that
module's breakpoints, telling its sites from other modules' by where
they are in the shared code image. But code inlined from one module
into another is in the other's code, so its breakpoints were decided
by the wrong module, and lost.

Record each breakpoint site's module (the innermost frame's, so
inlined code keeps its own) in the frame table, and re-patch by that
instead.
@sansmoraxz
sansmoraxz requested review from a team as code owners November 7, 2026 09:33
@sansmoraxz
sansmoraxz requested review from alexcrichton and removed request for a team November 7, 2026 09:33
@sansmoraxz sansmoraxz changed the title Keep a component's breakpoints in the module they were set in Debugging: Keep a component's breakpoints in the module they were set in Nov 7, 2026
@github-actions github-actions Bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Nov 7, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant