v0.4: INT3 software breakpoints with by-name/by-id ops
- StopReason::Breakpoint(id), rewinds RIP on hit - bp.set(addr_or_symbol, name?), bp.remove(id_or_name), bp.list() - step/cont disarm-step-rearm when PC sits on an enabled bp - fix: PIE load_base = mapping_base - mapping_file_offset (was using the first executable mapping with its offset, which is wrong on toolchains that split read-only header pages)
This commit is contained in:
@@ -365,6 +365,87 @@ fn install_globals<'js>(
|
||||
globals.set("symbols", f)?;
|
||||
}
|
||||
|
||||
// ---------- breakpoint / bp ---------------------------------------------
|
||||
// breakpoint.set(target, name?) → id (target = address number/BigInt or symbol name)
|
||||
// breakpoint.remove(id_or_name)
|
||||
// breakpoint.list() → [{id, addr, name, hits, enabled}]
|
||||
{
|
||||
let bp_obj = Object::new(c.clone())?;
|
||||
|
||||
// set(target, name?)
|
||||
{
|
||||
let target = target.clone();
|
||||
let f = Function::new(c.clone(), move |c: Ctx<'js>, location: Value<'js>, name: rquickjs::function::Opt<String>| -> rquickjs::Result<u32> {
|
||||
let mut slot = target.borrow_mut();
|
||||
let t = slot.as_mut().ok_or_else(|| throw(&c, "no target attached"))?;
|
||||
// location: string → resolve via symbols; number/BigInt → coerce_addr.
|
||||
let addr = if let Some(s) = location.clone().into_string() {
|
||||
let s = s.to_string()?;
|
||||
let sym = t.symbols().ok_or_else(|| throw(&c, "no symbol table"))?;
|
||||
sym.addr_for_name(&s).ok_or_else(|| throw(&c, &format!("unknown symbol: {}", s)))?
|
||||
} else {
|
||||
coerce_addr(&c, &location)?
|
||||
};
|
||||
let name = name.0;
|
||||
t.breakpoint_set(addr, name).map_err(|e| throw(&c, &e))
|
||||
})?;
|
||||
bp_obj.set("set", f)?;
|
||||
}
|
||||
|
||||
// remove(id_or_name)
|
||||
{
|
||||
let target = target.clone();
|
||||
let f = Function::new(c.clone(), move |c: Ctx<'js>, id_or_name: Value<'js>| -> rquickjs::Result<()> {
|
||||
let mut slot = target.borrow_mut();
|
||||
let t = slot.as_mut().ok_or_else(|| throw(&c, "no target attached"))?;
|
||||
let id = if let Some(s) = id_or_name.clone().into_string() {
|
||||
let s = s.to_string()?;
|
||||
t.breakpoint_id_by_name(&s).ok_or_else(|| throw(&c, &format!("no breakpoint named '{}'", s)))?
|
||||
} else if let Some(n) = id_or_name.as_number() {
|
||||
if n < 0.0 || n.fract() != 0.0 {
|
||||
return Err(throw(&c, "bp id must be a non-negative integer"));
|
||||
}
|
||||
n as u32
|
||||
} else if id_or_name.is_int() {
|
||||
let i: i32 = id_or_name.get()?;
|
||||
if i < 0 { return Err(throw(&c, "bp id must be non-negative")); }
|
||||
i as u32
|
||||
} else {
|
||||
return Err(throw(&c, "bp.remove expects id (number) or name (string)"));
|
||||
};
|
||||
t.breakpoint_remove(id).map_err(|e| throw(&c, &e))
|
||||
})?;
|
||||
bp_obj.set("remove", f)?;
|
||||
}
|
||||
|
||||
// list() → array of breakpoint records
|
||||
{
|
||||
let target = target.clone();
|
||||
let f = Function::new(c.clone(), 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 arr = rquickjs::Array::new(c.clone())?;
|
||||
for (i, bp) in t.breakpoints().iter().enumerate() {
|
||||
let rec = Object::new(c.clone())?;
|
||||
rec.set("id", bp.id)?;
|
||||
rec.set("addr", u64_to_bigint(&c, bp.addr)?)?;
|
||||
rec.set("hits", u64_to_bigint(&c, bp.hits)?)?;
|
||||
rec.set("enabled", bp.enabled)?;
|
||||
match &bp.name {
|
||||
Some(n) => rec.set("name", n.as_str())?,
|
||||
None => rec.set("name", Value::new_null(c.clone()))?,
|
||||
};
|
||||
arr.set(i, rec)?;
|
||||
}
|
||||
Ok(arr.into_value())
|
||||
})?;
|
||||
bp_obj.set("list", f)?;
|
||||
}
|
||||
|
||||
globals.set("breakpoint", bp_obj.clone())?;
|
||||
globals.set("bp", bp_obj)?;
|
||||
}
|
||||
|
||||
// ---------- JS-side prelude ---------------------------------------------
|
||||
// Loaded last, so it can reference any of the native globals above.
|
||||
// Lives in src/prelude.js, embedded at compile time.
|
||||
|
||||
Reference in New Issue
Block a user