add windows exception handling in C (#175)

This commit is contained in:
Mackenzie Clark
2019-02-14 09:58:33 -08:00
committed by GitHub
parent 0d7b5c8af6
commit 6a1fdb7f91
21 changed files with 630 additions and 32 deletions

View File

@ -223,9 +223,9 @@ impl FuncResolverBuilder {
LibCall::TruncF64 => libcalls::truncf64 as isize,
LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
#[cfg(all(target_pointer_width = "64", target_os = "windows"))]
Probestack => __chkstk as isize,
LibCall::Probestack => __chkstk as isize,
#[cfg(not(target_os = "windows"))]
Probestack => __rust_probestack as isize,
LibCall::Probestack => __rust_probestack as isize,
},
RelocationType::Intrinsic(ref name) => match name.as_str() {
"i32print" => i32_print as isize,

View File

@ -110,6 +110,7 @@ impl ProtectedCaller for Caller {
.lookup(sig_index)
.expect("that trampoline doesn't exist");
#[cfg(not(target_os = "windows"))]
call_protected(&self.handler_data, || unsafe {
// Leap of faith.
trampoline(
@ -120,6 +121,17 @@ impl ProtectedCaller for Caller {
);
})?;
// the trampoline is called from C on windows
#[cfg(target_os = "windows")]
call_protected(
&self.handler_data,
trampoline,
vmctx_ptr,
func_ptr,
param_vec.as_ptr(),
return_vec.as_mut_ptr(),
)?;
Ok(return_vec
.iter()
.zip(signature.returns().iter())

View File

@ -1,10 +1,116 @@
use crate::relocation::{TrapCode, TrapData};
use crate::signal::HandlerData;
use wasmer_runtime_core::error::RuntimeResult;
use crate::trampoline::Trampoline;
use std::cell::Cell;
use std::ffi::c_void;
use std::ptr;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::vm::Func;
use wasmer_runtime_core::{
error::{RuntimeError, RuntimeResult},
structures::TypedIndex,
types::{MemoryIndex, TableIndex},
};
use wasmer_win_exception_handler::CallProtectedData;
pub use wasmer_win_exception_handler::_call_protected;
use winapi::shared::minwindef::DWORD;
use winapi::um::minwinbase::{
EXCEPTION_ACCESS_VIOLATION, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW,
EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_ILLEGAL_INSTRUCTION,
EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_STACK_OVERFLOW,
};
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
unimplemented!("TODO");
thread_local! {
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
}
pub fn call_protected(
handler_data: &HandlerData,
trampoline: Trampoline,
ctx: *mut Ctx,
func: *const Func,
param_vec: *const u64,
return_vec: *mut u64,
) -> RuntimeResult<()> {
// TODO: trap early
// user code error
// if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
// return Err(RuntimeError::User { msg });
// }
let result = _call_protected(trampoline, ctx, func, param_vec, return_vec);
if let Ok(_) = result {
return Ok(());
}
let CallProtectedData {
code: signum,
exceptionAddress: exception_address,
instructionPointer: instruction_pointer,
} = result.unwrap_err();
if let Some(TrapData {
trapcode,
srcloc: _,
}) = handler_data.lookup(instruction_pointer as _)
{
Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
},
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
table: TableIndex::new(0),
},
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
table: TableIndex::new(0),
},
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
},
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
table: TableIndex::new(0),
},
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
},
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation,
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation,
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
},
}
.into())
} else {
let signal = match signum as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND
| EXCEPTION_FLT_DIVIDE_BY_ZERO
| EXCEPTION_FLT_INEXACT_RESULT
| EXCEPTION_FLT_INVALID_OPERATION
| EXCEPTION_FLT_OVERFLOW
| EXCEPTION_FLT_STACK_CHECK
| EXCEPTION_FLT_UNDERFLOW => "floating-point exception",
EXCEPTION_ILLEGAL_INSTRUCTION => "illegal instruction",
EXCEPTION_ACCESS_VIOLATION => "segmentation violation",
_ => "unkown trapped signal",
};
Err(RuntimeError::Unknown {
msg: format!("trap at {} - {}", exception_address, signal),
}
.into())
}
}
pub unsafe fn trigger_trap() -> ! {
unimplemented!("TODO");
// TODO
unimplemented!();
}

View File

@ -7,6 +7,7 @@ use cranelift_codegen::{
isa, Context,
};
use hashbrown::HashMap;
use std::ffi::c_void;
use std::{iter, mem};
use wasmer_runtime_core::{
backend::sys::{Memory, Protect},
@ -23,6 +24,9 @@ impl RelocSink for NullRelocSink {
fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {}
}
pub type Trampoline =
unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64) -> c_void;
pub struct Trampolines {
memory: Memory,
offsets: HashMap<SigIndex, usize>,
@ -138,10 +142,7 @@ impl Trampolines {
}
}
pub fn lookup(
&self,
sig_index: SigIndex,
) -> Option<unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64)> {
pub fn lookup(&self, sig_index: SigIndex) -> Option<Trampoline> {
let offset = *self.offsets.get(&sig_index)?;
let ptr = unsafe { self.memory.as_ptr().add(offset) };
@ -212,7 +213,9 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type {
}
fn generate_trampoline_signature() -> ir::Signature {
let mut sig = ir::Signature::new(isa::CallConv::SystemV);
let isa = super::get_isa();
let call_convention = isa.default_call_conv();
let mut sig = ir::Signature::new(call_convention);
let ptr_param = ir::AbiParam {
value_type: ir::types::I64,
@ -227,7 +230,9 @@ fn generate_trampoline_signature() -> ir::Signature {
}
fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
let mut export_clif_sig = ir::Signature::new(isa::CallConv::SystemV);
let isa = super::get_isa();
let call_convention = isa.default_call_conv();
let mut export_clif_sig = ir::Signature::new(call_convention);
let func_sig_iter = func_sig.params().iter().map(|wasm_ty| ir::AbiParam {
value_type: wasm_ty_to_clif(*wasm_ty),