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

@ -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!();
}