Misc cleanups in the trap handling code.
This commit is contained in:
@@ -15,7 +15,6 @@ fn main() {
|
|||||||
|
|
||||||
let mut bindings_builder = bindgen::Builder::default()
|
let mut bindings_builder = bindgen::Builder::default()
|
||||||
.header("signalhandlers/SignalHandlers.h")
|
.header("signalhandlers/SignalHandlers.h")
|
||||||
.whitelist_type("CodeSegment")
|
|
||||||
.whitelist_type("TrapContext")
|
.whitelist_type("TrapContext")
|
||||||
.whitelist_type("jmp_buf")
|
.whitelist_type("jmp_buf")
|
||||||
.whitelist_function("EnsureEagerSignalHandlers");
|
.whitelist_function("EnsureEagerSignalHandlers");
|
||||||
|
|||||||
@@ -406,13 +406,7 @@ HandleTrap(CONTEXT* context)
|
|||||||
{
|
{
|
||||||
assert(sAlreadyHandlingTrap);
|
assert(sAlreadyHandlingTrap);
|
||||||
|
|
||||||
const uint8_t* pc = ContextToPC(context);
|
RecordTrap(ContextToPC(context));
|
||||||
const CodeSegment* codeSegment = LookupCodeSegment(pc);
|
|
||||||
if (!codeSegment) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordTrap(pc, codeSegment);
|
|
||||||
|
|
||||||
// Unwind calls longjmp, so it doesn't run the automatic
|
// Unwind calls longjmp, so it doesn't run the automatic
|
||||||
// sAlreadhHanldingTrap cleanups, so reset it manually before doing
|
// sAlreadhHanldingTrap cleanups, so reset it manually before doing
|
||||||
|
|||||||
@@ -11,19 +11,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct CodeSegment;
|
|
||||||
|
|
||||||
// Record the Trap code and wasm bytecode offset in TLS somewhere
|
// Record the Trap code and wasm bytecode offset in TLS somewhere
|
||||||
void RecordTrap(const uint8_t* pc, const struct CodeSegment* codeSegment);
|
void RecordTrap(const uint8_t* pc);
|
||||||
|
|
||||||
// Initiate an unwind.
|
// Initiate an unwind.
|
||||||
void Unwind(void);
|
void Unwind(void);
|
||||||
|
|
||||||
// Return the CodeSegment containing the given pc, if any exist in the process.
|
|
||||||
// This method does not take a lock.
|
|
||||||
const struct CodeSegment*
|
|
||||||
LookupCodeSegment(const void* pc);
|
|
||||||
|
|
||||||
// Trap initialization state.
|
// Trap initialization state.
|
||||||
struct TrapContext {
|
struct TrapContext {
|
||||||
bool triedToInstallSignalHandlers;
|
bool triedToInstallSignalHandlers;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//! signalhandling mechanisms.
|
//! signalhandling mechanisms.
|
||||||
|
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use signalhandlers::{jmp_buf, CodeSegment};
|
use signalhandlers::jmp_buf;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
@@ -19,13 +19,8 @@ extern "C" {
|
|||||||
fn longjmp(env: *const jmp_buf, val: c_int) -> !;
|
fn longjmp(env: *const jmp_buf, val: c_int) -> !;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
struct TrapData {
|
|
||||||
pc: *const u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static TRAP_DATA: Cell<TrapData> = Cell::new(TrapData { pc: ptr::null() });
|
static TRAP_PC: Cell<*const u8> = Cell::new(ptr::null());
|
||||||
static JMP_BUFS: RefCell<Vec<jmp_buf>> = RefCell::new(Vec::new());
|
static JMP_BUFS: RefCell<Vec<jmp_buf>> = RefCell::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +28,9 @@ thread_local! {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn RecordTrap(pc: *const u8, _codeSegment: *const CodeSegment) {
|
pub extern "C" fn RecordTrap(pc: *const u8) {
|
||||||
// TODO: Look up the wasm bytecode offset and trap code and record them instead.
|
// TODO: Look up the wasm bytecode offset and trap code and record them instead.
|
||||||
TRAP_DATA.with(|data| data.set(TrapData { pc }));
|
TRAP_PC.with(|data| data.set(pc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate an unwind.
|
/// Initiate an unwind.
|
||||||
@@ -49,16 +44,6 @@ pub extern "C" fn Unwind() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the CodeSegment containing the given pc, if any exist in the process.
|
|
||||||
/// This method does not take a lock.
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn LookupCodeSegment(_pc: *const ::std::os::raw::c_void) -> *const CodeSegment {
|
|
||||||
// TODO: Implement this.
|
|
||||||
-1isize as *const CodeSegment
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple guard to ensure that `JMP_BUFS` is reset when we're done.
|
/// A simple guard to ensure that `JMP_BUFS` is reset when we're done.
|
||||||
struct ScopeGuard {
|
struct ScopeGuard {
|
||||||
orig_num_bufs: usize,
|
orig_num_bufs: usize,
|
||||||
@@ -66,6 +51,11 @@ struct ScopeGuard {
|
|||||||
|
|
||||||
impl ScopeGuard {
|
impl ScopeGuard {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
assert_eq!(
|
||||||
|
TRAP_PC.with(|data| data.get()),
|
||||||
|
ptr::null(),
|
||||||
|
"unfinished trap detected"
|
||||||
|
);
|
||||||
Self {
|
Self {
|
||||||
orig_num_bufs: JMP_BUFS.with(|bufs| bufs.borrow().len()),
|
orig_num_bufs: JMP_BUFS.with(|bufs| bufs.borrow().len()),
|
||||||
}
|
}
|
||||||
@@ -82,6 +72,19 @@ impl Drop for ScopeGuard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trap_message(_vmctx: *mut VMContext) -> String {
|
||||||
|
let pc = TRAP_PC.with(|data| data.replace(ptr::null()));
|
||||||
|
|
||||||
|
// TODO: Record trap metadata in the VMContext, and look up the
|
||||||
|
// pc to obtain the TrapCode and SourceLoc.
|
||||||
|
|
||||||
|
format!("wasm trap at {:?}", pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_jmp_buf(buf: jmp_buf) {
|
||||||
|
JMP_BUFS.with(|bufs| bufs.borrow_mut().push(buf));
|
||||||
|
}
|
||||||
|
|
||||||
/// Call the wasm function pointed to by `callee`. `values_vec` points to
|
/// Call the wasm function pointed to by `callee`. `values_vec` points to
|
||||||
/// a buffer which holds the incoming arguments, and to which the outgoing
|
/// a buffer which holds the incoming arguments, and to which the outgoing
|
||||||
/// return values will be written.
|
/// return values will be written.
|
||||||
@@ -91,21 +94,21 @@ pub unsafe extern "C" fn wasmtime_call_trampoline(
|
|||||||
values_vec: *mut u8,
|
values_vec: *mut u8,
|
||||||
vmctx: *mut VMContext,
|
vmctx: *mut VMContext,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// In case wasm code calls Rust that panics and unwinds past this point,
|
// Reset JMP_BUFS if the stack is unwound through this point.
|
||||||
// ensure that JMP_BUFS is unwound to its incoming state.
|
|
||||||
let _guard = ScopeGuard::new();
|
let _guard = ScopeGuard::new();
|
||||||
|
|
||||||
let func: fn(*mut u8, *mut VMContext) = mem::transmute(callee);
|
// Set a setjmp catch point.
|
||||||
|
|
||||||
JMP_BUFS.with(|bufs| {
|
|
||||||
let mut buf = mem::uninitialized();
|
let mut buf = mem::uninitialized();
|
||||||
if setjmp(&mut buf) != 0 {
|
if setjmp(&mut buf) != 0 {
|
||||||
return TRAP_DATA.with(|data| Err(format!("wasm trap at {:?}", data.get().pc)));
|
return Err(trap_message(vmctx));
|
||||||
}
|
}
|
||||||
bufs.borrow_mut().push(buf);
|
push_jmp_buf(buf);
|
||||||
|
|
||||||
|
// Call the function!
|
||||||
|
let func: fn(*mut u8, *mut VMContext) = mem::transmute(callee);
|
||||||
func(values_vec, vmctx);
|
func(values_vec, vmctx);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the wasm function pointed to by `callee`, which has no arguments or
|
/// Call the wasm function pointed to by `callee`, which has no arguments or
|
||||||
@@ -115,19 +118,19 @@ pub unsafe extern "C" fn wasmtime_call(
|
|||||||
callee: *const VMFunctionBody,
|
callee: *const VMFunctionBody,
|
||||||
vmctx: *mut VMContext,
|
vmctx: *mut VMContext,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// In case wasm code calls Rust that panics and unwinds past this point,
|
// Reset JMP_BUFS if the stack is unwound through this point.
|
||||||
// ensure that JMP_BUFS is unwound to its incoming state.
|
|
||||||
let _guard = ScopeGuard::new();
|
let _guard = ScopeGuard::new();
|
||||||
|
|
||||||
let func: fn(*mut VMContext) = mem::transmute(callee);
|
// Set a setjmp catch point.
|
||||||
|
|
||||||
JMP_BUFS.with(|bufs| {
|
|
||||||
let mut buf = mem::uninitialized();
|
let mut buf = mem::uninitialized();
|
||||||
if setjmp(&mut buf) != 0 {
|
if setjmp(&mut buf) != 0 {
|
||||||
return TRAP_DATA.with(|data| Err(format!("wasm trap at {:?}", data.get().pc)));
|
return Err(trap_message(vmctx));
|
||||||
}
|
}
|
||||||
bufs.borrow_mut().push(buf);
|
push_jmp_buf(buf);
|
||||||
|
|
||||||
|
// Call the function!
|
||||||
|
let func: fn(*mut VMContext) = mem::transmute(callee);
|
||||||
func(vmctx);
|
func(vmctx);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user