page: ?fjitlibs= rules also keep other objects' callees out of a module; the wild-branch diagnostic shows open call-outs, the named stack and registers

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_1896c5b302a54696aaa92c5f4047f20b
This commit is contained in:
velzieandClaude Opus 5.5 committed 2026-10-08 18:40:28 -04:00
1 parent afb35e250e
commit 7e23c82a56
3 files changed
+23 -1

No files matched your search

+8
View File
@@ -1298,6 +1298,14 @@ pub extern "C" fn gex_ftab_fallback(ctx: i32, _depth: i32, _need: i32, ret: i64)
c.len() - 1
});
CALLOUT_N.fetch_add(1, Ordering::Relaxed);
// Opened (result -1): one that never closes was abandoned by a throw.
CALLOUT_RING.with(|x| {
let mut x = x.borrow_mut();
if x.len() >= 24 {
x.remove(0);
}
x.push((t, ret as u64, want, depth as u32, -1, sp));
});
// SAFETY: a host import taking scalars; nothing here holds a lock.
let r = unsafe { call_out(ctx, t as i64, ret, want as i64) };
CALLOUTS.with(|c| c.borrow_mut().truncate(depth));
+5 -1
View File
@@ -157,7 +157,11 @@ pub(crate) fn translate(addr: u64) -> Option<u32> {
return None;
}
// An address an ELF provider holds is not code to translate (cgen::elfprov).
let executable = |a: u64| exec.iter().any(|&(s, e)| a >= s && a < e) && !crate::cgen::elfprov::provided(a) && !crate::cgen::libprov::replaced(a);
// With `?fjitlibs=` rules, callees outside them are not brought in either.
let rules = !lock(&LIBS).is_empty();
let executable = |a: u64| {
exec.iter().any(|&(s, e)| a >= s && a < e) && !crate::cgen::elfprov::provided(a) && !crate::cgen::libprov::replaced(a) && (!rules || lib_wanted(a))
};
let read_only = |a: u64, n: u64| ro.iter().any(|&(s, e)| a >= s && a.saturating_add(n) <= e);
// Writable-and-executable code (a JIT's) stays tier-1, as natively.
let volatile = |a: u64| wx.iter().any(|&(s, e)| a >= s && a < e);
+10
View File
@@ -10967,6 +10967,16 @@ pub extern "C" fn gex_dispatch_miss(_ctx: i32, pc: i64) -> i32 {
let stack: Vec<String> = (0..8)
.map(|i| format!("{:#x}", gm.read_u64(sp + i * 8).unwrap_or(0)))
.collect();
// The stack around sp, named, and the registers (a bad return's frame).
let around: Vec<String> = (0..24u64)
.map(|i| {
let a = sp.wrapping_sub(0x60).wrapping_add(i * 8);
let v = gm.read_u64(a).unwrap_or(0);
format!("{a:#x}={v:#x}{}", Some(object_off_at(h, v)).filter(|n| !n.is_empty()).map(|n| format!(" ({n})")).unwrap_or_default())
})
.collect();
let regs: Vec<String> = (0..16u8).map(|r| format!("r{r}={:#x}", gm.read_u64(c + ctx::x(r) as u64).unwrap_or(0))).collect();
warn_line(&format!("[gex] wild branch: stack {}; regs {}\n", around.join(", "), regs.join(" ")));
warn_line(&format!(
"[gex] pid {} thread {} branched to {pc:#x}, which is not executable guest memory (SIGSEGV); last indirect target {last:#x} ({}) from block {src:#x} ({}), sp={sp:#x} stack=[{}], last syscall {}\n",
h.kernel.pid,