Save exit Wasm FP and PC in component-to-host trampolines (#4601)

* Wasmtime: Add a pointer to `VMRuntimeLimits` in component contexts

* Save exit Wasm FP and PC in component-to-host trampolines

Fixes #4535

* Add comment about why we deref the trampoline's FP

* Update some tests to use new `vmruntime_limits_*` methods
This commit is contained in:
Nick Fitzgerald
2022-08-04 08:27:30 -07:00
committed by GitHub
parent f69acd6187
commit 70ce288dc7
16 changed files with 206 additions and 149 deletions

View File

@@ -114,6 +114,7 @@ impl Backtrace {
trap_pc_and_fp: Option<(usize, usize)>,
mut f: impl FnMut(Frame) -> ControlFlow<()>,
) {
log::trace!("====== Capturing Backtrace ======");
let (last_wasm_exit_pc, last_wasm_exit_fp) = match trap_pc_and_fp {
// If we exited Wasm by catching a trap, then the Wasm-to-host
// trampoline did not get a chance to save the last Wasm PC and FP,
@@ -137,6 +138,7 @@ impl Backtrace {
*(*state.limits).last_wasm_entry_sp.get(),
&mut f,
) {
log::trace!("====== Done Capturing Backtrace ======");
return;
}
@@ -151,6 +153,7 @@ impl Backtrace {
debug_assert_eq!(state.old_last_wasm_exit_pc, 0);
debug_assert_eq!(state.old_last_wasm_exit_fp, 0);
debug_assert_eq!(state.old_last_wasm_entry_sp, 0);
log::trace!("====== Done Capturing Backtrace ======");
return;
}
@@ -160,9 +163,12 @@ impl Backtrace {
state.old_last_wasm_entry_sp,
&mut f,
) {
log::trace!("====== Done Capturing Backtrace ======");
return;
}
}
unreachable!()
}
/// Walk through a contiguous sequence of Wasm frames starting with the
@@ -245,7 +251,13 @@ impl Backtrace {
pc = arch::get_next_older_pc_from_fp(fp);
let next_older_fp = arch::get_next_older_fp_from_fp(fp);
// We rely on this offset being zero for all supported architectures
// in `crates/cranelift/src/component/compiler.rs` when we set the
// Wasm exit FP. If this ever changes, we will need to update that
// code as well!
assert_eq!(arch::NEXT_OLDER_FP_FROM_FP_OFFSET, 0);
let next_older_fp = *(fp as *mut usize).add(arch::NEXT_OLDER_FP_FROM_FP_OFFSET);
// Because the stack always grows down, the older FP must be greater
// than the current FP.
assert!(next_older_fp > fp, "{next_older_fp:#x} > {fp:#x}");

View File

@@ -30,9 +30,9 @@ pub unsafe fn get_next_older_pc_from_fp(fp: usize) -> usize {
pc
}
pub unsafe fn get_next_older_fp_from_fp(fp: usize) -> usize {
*(fp as *mut usize)
}
// And the current frame pointer points to the next older frame pointer.
pub const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = 0;
pub fn reached_entry_sp(fp: usize, first_wasm_sp: usize) -> bool {
// Calls in aarch64 push two i64s (old FP and return PC) so our entry SP is

View File

@@ -5,11 +5,9 @@ pub unsafe fn get_next_older_pc_from_fp(fp: usize) -> usize {
*(fp as *mut usize).offset(14)
}
pub unsafe fn get_next_older_fp_from_fp(fp: usize) -> usize {
// The next older "FP" (backchain pointer) was saved in the slot pointed to
// by the current "FP".
*(fp as *mut usize)
}
// The next older "FP" (backchain pointer) was saved in the slot pointed to
// by the current "FP".
pub const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = 0;
pub fn reached_entry_sp(fp: usize, first_wasm_sp: usize) -> bool {
// The "FP" (backchain pointer) holds the value of the stack pointer at

View File

@@ -4,10 +4,8 @@ pub unsafe fn get_next_older_pc_from_fp(fp: usize) -> usize {
*(fp as *mut usize).offset(1)
}
pub unsafe fn get_next_older_fp_from_fp(fp: usize) -> usize {
// And the current frame pointer points to the next older frame pointer.
*(fp as *mut usize)
}
// And the current frame pointer points to the next older frame pointer.
pub const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = 0;
pub fn reached_entry_sp(fp: usize, first_wasm_sp: usize) -> bool {
// When the FP is just below the SP (because we are in a function prologue