v0.6: state.stack, until(loc), finish(), prelude show.* helpers

- StackRegion from /proc/<pid>/maps, exposed as state.stack
  ({top, usable_base, guard_size} BigInts per spec)
- until(loc) one-shot bp wrapper that cleans up via try/finally,
  works even if a different stop fires first
- finish() reads return address from [rbp+8] and uses until()
- updated js.rs module doc; allow(dead_code) on the kept-for-future
  BreakpointSet::find_by_name
This commit is contained in:
claude
2026-05-27 21:30:18 +00:00
parent 2ed17f0286
commit 2f64981729
5 changed files with 121 additions and 11 deletions
+34 -9
View File
@@ -1,15 +1,22 @@
//! QuickJS REPL: persistent context, ptrace target lives behind an Rc<RefCell>,
//! globals are installed once at construction.
//!
//! v0.1 surface:
//! spawn(path, ...args) -> { pid, status }
//! step(n=1) -> stop-reason string
//! continue() -> stop-reason string (exposed as `continue` and `cont`)
//! print(...args) -> writes to stdout
//! ctx -> persistent plain object
//! state.pc / .sp -> BigInt
//! state.registers -> object of BigInts
//! state.memory(addr) -> { u8(), u32(), u64(), i64(), bytes(n) }
//! Native globals installed here:
//! spawn(path, ...args) -> { pid, status }
//! step(n=1) / cont() -> stop-reason string
//! print(...args), ctx (persistent object)
//! state.pc, state.sp -> BigInt (live ptrace)
//! state.registers -> object of BigInts
//! state.memory(addr) -> { u8/u32/u64/i64/bytes }
//! state.disasm(n=8) -> [{addr, bytes, text, target?, target_sym?}]
//! state.stack -> { top, usable_base, guard_size }
//! prev -> register snapshot from before last resume
//! sym(addr), addr(name), symbols()
//! disasm(addr, n=8)
//! breakpoint / bp: .set, .remove, .list
//!
//! JS-side helpers (in prelude.js): hex, unhex, dump, repr, addrstr, here,
//! until, finish, show.{disasm,bp,regs}.
use crate::target::Target;
use rquickjs::function::Rest;
@@ -314,6 +321,24 @@ fn install_globals<'js>(
state_obj.set("disasm", f)?;
}
// state.stack — accessor returning {top, usable_base, guard_size} as BigInts
{
let target = target.clone();
state_obj.prop(
"stack",
Accessor::from(move |c: Ctx<'js>| -> rquickjs::Result<Value<'js>> {
let slot = target.borrow();
let t = slot.as_ref().ok_or_else(|| throw(&c, "no target attached"))?;
let s = t.stack().ok_or_else(|| throw(&c, "no stack info"))?;
let obj = Object::new(c.clone())?;
obj.set("top", u64_to_bigint(&c, s.high)?)?;
obj.set("usable_base", u64_to_bigint(&c, s.low)?)?;
obj.set("guard_size", u64_to_bigint(&c, s.guard_size)?)?;
Ok(obj.into_value())
}),
)?;
}
globals.set("state", state_obj)?;
}