3 Commits
Author SHA1 Message Date
llmdbg-dev f7a2cd0600 docs: field notes from smarm context-switch session (v0.8)
Friction-and-wishlist from one real profiling/verification session, not a
defect report. Highlights: demangling and trace({over,capture}) worked well;
pc-range checks are treacherous when helpers sit adjacent to the function
under test (symbol extent, not address, is the missing primitive); no
float/vector register access forced the XMM verification out to objdump.

Wishlist, JS-expressible first: symStart/symSize (or inFn), countTo, hexdump
— candidates for a v0.9 prelude with no Rust changes. xmm reads and
prologue-aware breakpoints need native support.
2026-05-28 15:19:43 +00:00
llmdbg-dev f0698573cd v0.8: step-over (next/trace), symbol demangling, disasm len/is_call, ergonomics
Driven by the friction the v0.7 smarm session hit: single-stepping the
context-switch shim dove into every helper call, and every step needed
`nm | grep` for a mangled name whose hash changes each rebuild. This round
makes tracing the shim pleasant.

Rust (kept minimal — only what JS genuinely can't do):
- symbols.rs: demangle Rust symbols. addr("name") now resolves by exact
  mangled/case-insensitive (unchanged), then by full demangled path
  (smarm::context::switch_to_scheduler), then by *unique* final path
  component (switch_to_scheduler). Ambiguous short names resolve to None and
  bp.set reports "matches N symbols" rather than guessing. sym()/name_for_addr
  return demangled names so traces are readable. Adds rustc-demangle dep.
- disasm.rs: Decoded gains `len` (instruction byte length) and `is_call`
  (iced FlowControl::Call, incl. indirect). js.rs exposes both on disasm
  records so step-over finds the return address without re-parsing text.

Prelude (everything else, like until/finish):
- next(n): step OVER calls — one-shot bp at pc+len, cont, cleanup; else
  single-step. A stepped-over call fires the `step` listener once. Detects
  calls that don't return to pc+len (stack-switching shims, longjmp): on a
  non-matching stop it dispatches the real event and stops instead of hanging.
- trace(from, to, {over, range, capture, print, max}): run-to-A then
  step(-over)-to-B with per-step capture; `range:[lo,hi]` stops when pc leaves
  a range. Drives the native steppers directly (no listener coupling).
- watch(specs): a `step` listener printing named expressions each step.
- fmt(): BigInt-safe stringify. state.insn: disasm record at pc.
  stackContains/stackDistance/region: stack-region legibility for cross-stack
  handoffs. step(n, {summary}): first/last/count for large N.

Docs: README status row + prelude reference + sections on the next() caveat,
the conditional-breakpoint listener idiom, and BigInt ergonomics.
examples/smarm_ctx_switch_next.js traces a full switch_to_scheduler in 16
readable lines using trace({over:true}).

No-listener fast paths and the v0.7 example are unaffected (verified).
2026-05-28 06:20:43 +00:00
llmdbg-dev ce96a98829 v0.7: event-listener system (addEventListener/step/breakpoint/signal/exit)
- Native step/cont moved to __step_native/__cont_native; public step()/cont()
  defined in prelude.js wrap them and dispatch JS listeners on each stop.
- addEventListener/removeEventListener/clearListeners/listeners() registry on
  globalThis, persistent for the daemon lifetime (independent of ctx.reset()).
- Event object carries {state, prev, stop_reason} plus breakpoint_id/signal/
  exit_code as appropriate. Implements the SPEC 'Event Listeners' + 'Core Loop'.
- No-listener fast path keeps existing scripts zero-cost.
- examples/smarm_ctx_switch.js: worked session inspecting smarm's naked-asm
  context switch; README updated (status table, listener API, deferred list).
2026-05-28 05:50:09 +00:00