alexcrichton opened issue #12995:
I'm trying to remember to kick the tires on
wasmtime -gmore often now that we have it baked in. I'm working on something in wasi-libc and my code is currently buggy so I wanted to explore a test case withlldb. The source code is here and poll-connect.wasm is the binary I'm working with.Reproducing this is in one window:
$ ../wasmtime/target/release/wasmtime -g1234 -W component-model-async -Sp3,inherit-network /home/alex/code/wasi-libc/build/p3/test/poll-connect.wasm Debugger: Debugger listening on 127.0.0.1:1234 Debugger: In LLDB, attach with: process connect --plugin wasm connect://127.0.0.1:1234and in another window:
$ $WASI_SDK_PATH/bin/lldb (lldb) process connect --plugin wasm connect://127.0.0.1:1234 Process 1 stopped * thread #1, stop reason = signal SIGTRAP frame #0: 0x00000000 error: memory read failed for 0x0 (lldb) b poll_impl Breakpoint 1: where = wasm-0`poll_impl + 51 at poll.c:334:31, address = 0x4000000000002c61 (lldb) c Process 1 resuming Process 1 stopped * thread #1, stop reason = breakpoint 1.1 frame #0: 0x4000000000002c61 wasm-0`poll_impl(fds=0x0000ff90, nfds=2, timeout=100) at poll.c:334:31 331 // revisited for wasip3. Maybe make this a dynamically allocated array? 332 size_t max_pollables = (2 * nfds) + 1; 333 state_t states[max_pollables]; -> 334 335 poll_state_t state; 336 state.set = wasip3_waitable_set_new(); 337 state.states = states; (lldb) n Process 1 stopped * thread #1, stop reason = signal SIGSEGV frame #0: 0x400000000000cd72 wasm-0`wasip3_waitable_set_drop(set=5) at wasip3.c:1232:1 1229 1230 void wasip3_waitable_set_drop(wasip3_waitable_set_t set) { 1231 __waitable_set_drop(set); -> 1232 } 1233 1234 __attribute__((__import_module__("$root"), __import_name__("[waitable-set-wait]"))) 1235 extern uint32_t __waitable_set_wait(uint32_t, uint32_t*);Specifically I'm trying to step through the
poll_implfunction and inspect local variables. Thencommand however continues all the way to the end which is a trap that's showing up. The trap is expected (that's the bug), but the lack of stepping is what this bug is about.This may very well be a bug in LLDB itself, but I figured I'd at least start here as our own support may be a bit more nascent than LLDB's.
alexcrichton added the wasmtime:debugging label to Issue #12995.
cfallin commented on issue #12995:
Here's a relevant snippet of the gdbstub protocol, between hitting the breakpoint and doing
n(obtained this via-Dinherit-stderr=true -Darg=-v):[2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $Z0,4000000000002c7b,1#85 [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $OK#9a [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $z0,4000000000002c61,1#73 [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $OK#9a [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $vCont;s:p1.1#f2 [2026-04-10T18:24:41Z TRACE wasmtime_internal_gdbstub_component::target] resume() -> single_stepping = true [2026-04-10T18:24:41Z TRACE wasmtime_internal_gdbstub_component] single-stepping [2026-04-10T18:24:41Z TRACE gdbstub::stub::state_machine] transition: "Idle<wasmtime_internal_gdbstub_component::Debugger<'_>>" --> "Running" [2026-04-10T18:24:41Z TRACE wasmtime_internal_gdbstub_component] Event::Breakpoint; single_stepping = true [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $T05thread:p01.01;00:632c000000000040;#bd [2026-04-10T18:24:41Z TRACE gdbstub::stub::state_machine] transition: "Running" --> "Idle<wasmtime_internal_gdbstub_component::Debugger<'_>>" [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $qfThreadInfo#bb [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $mp01.01#cd [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $qsThreadInfo#c8 [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $l#6c [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $Z0,4000000000002c61,1#53 [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $OK#9a [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $z0,4000000000002c7b,1#a5 [2026-04-10T18:24:41Z TRACE gdbstub::protocol::response_writer] --> $OK#9a [2026-04-10T18:24:41Z TRACE gdbstub::protocol::recv_packet] <-- $vCont;c:p1.-1#0f [2026-04-10T18:24:41Z TRACE wasmtime_internal_gdbstub_component::target] resume() -> single_stepping = false [2026-04-10T18:24:41Z TRACE wasmtime_internal_gdbstub_component] continuing [2026-04-10T18:24:41Z TRACE gdbstub::stub::state_machine] transition: "Idle<wasmtime_internal_gdbstub_component::Debugger<'_>>" --> "Running" [2026-04-10T18:24:41Z TRACE wasmtime_internal_gdbstub_component] Event::Trapin other words, we're paused at
0x2c61(poll_impl); I see LLDB set a breakpoint at 0x2c7b (Zcommand) then continued. Wasmtime came back with anEvent::Breakpointwith PC at0x2c63(indeed the next instruction); LLDB then disables the breakpoint at0x2c7band re-sets one at0x2c61(!!) and continues. We then keep running until we hit the trap.So this seems like an LLDB bug, and I'm not sure how much is actionable on our end, but I'll poke at a bit more to see why it's doing inexplicable things with breakpoints...
alexcrichton commented on issue #12995:
One possible issue reading over that log (thanks for the flags!) -- that's resuming after setting breakpoints with
single_stepping = true, but I think that's incorrect where shouldn'tsingle_steppingbefalse? I'm not sure if that's a LLDB or wasmtime-gdbstub thing though as to who decides the value ofsingle_stepping
cfallin commented on issue #12995:
Ah, yes, that's the
sorcinvCont;sorvCont;c-- LLDB tells us which to do.
Last updated: Apr 12 2026 at 23:10 UTC