mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 22:25:40 +00:00
Implemented protected call and floating point traps; passing all spectests!
This commit is contained in:
parent
1f8c644855
commit
f8fe999015
@ -14,3 +14,5 @@ dynasm = "0.3.0"
|
||||
dynasmrt = "0.3.1"
|
||||
lazy_static = "1.2.0"
|
||||
byteorder = "1"
|
||||
nix = "0.13.0"
|
||||
libc = "0.2.49"
|
||||
|
@ -9,6 +9,7 @@ use wasmer_runtime_core::{
|
||||
use wasmparser::{Operator, Type as WpType};
|
||||
|
||||
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator, PC: ProtectedCaller, FR: FuncResolver> {
|
||||
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError>;
|
||||
fn next_function(&mut self) -> Result<&mut FCG, CodegenError>;
|
||||
fn finalize(self, module_info: &ModuleInfo) -> Result<(PC, FR), CodegenError>;
|
||||
fn feed_signatures(
|
||||
|
@ -24,6 +24,7 @@ use wasmer_runtime_core::{
|
||||
vm::{self, ImportBacking, LocalGlobal, LocalTable, LocalMemory},
|
||||
};
|
||||
use wasmparser::{Operator, Type as WpType};
|
||||
use crate::protect_unix;
|
||||
|
||||
thread_local! {
|
||||
static CURRENT_EXECUTION_CONTEXT: RefCell<Vec<*const X64ExecutionContext>> = RefCell::new(Vec::new());
|
||||
@ -384,17 +385,21 @@ impl ProtectedCaller for X64ExecutionContext {
|
||||
CURRENT_EXECUTION_CONTEXT.with(|x| x.borrow_mut().push(self));
|
||||
|
||||
let ret = unsafe {
|
||||
CALL_WASM(
|
||||
param_buf.as_ptr(),
|
||||
param_buf.len(),
|
||||
ptr,
|
||||
memory_base,
|
||||
_vmctx,
|
||||
)
|
||||
protect_unix::call_protected(|| {
|
||||
CALL_WASM(
|
||||
param_buf.as_ptr(),
|
||||
param_buf.len(),
|
||||
ptr,
|
||||
memory_base,
|
||||
_vmctx,
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
CURRENT_EXECUTION_CONTEXT.with(|x| x.borrow_mut().pop().unwrap());
|
||||
|
||||
let ret = ret?;
|
||||
|
||||
Ok(if let Some(ty) = return_ty {
|
||||
vec![match ty {
|
||||
WpType::I32 => Value::I32(ret as i32),
|
||||
@ -524,6 +529,19 @@ impl X64ModuleCodeGenerator {
|
||||
}
|
||||
|
||||
impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, X64RuntimeResolver> for X64ModuleCodeGenerator {
|
||||
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError> {
|
||||
for mem in module_info.memories.iter().map(|(_, v)| v).chain(module_info.imported_memories.iter().map(|(_, v)| &v.1)) {
|
||||
match mem.memory_type() {
|
||||
MemoryType::Dynamic => return Err(CodegenError {
|
||||
message: "dynamic memory isn't supported yet"
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> {
|
||||
let (mut assembler, mut function_labels, br_table_data) = match self.functions.last_mut() {
|
||||
Some(x) => (
|
||||
@ -1428,6 +1446,98 @@ impl X64FunctionCode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_f32_int_conv_check(
|
||||
assembler: &mut Assembler,
|
||||
reg: Register,
|
||||
lower_bound: f32,
|
||||
upper_bound: f32,
|
||||
) {
|
||||
let lower_bound = f32::to_bits(lower_bound);
|
||||
let upper_bound = f32::to_bits(upper_bound);
|
||||
|
||||
dynasm!(
|
||||
assembler
|
||||
; movq xmm5, r15
|
||||
|
||||
// underflow
|
||||
; movd xmm1, Rd(reg as u8)
|
||||
; mov r15d, lower_bound as i32
|
||||
; movd xmm2, r15d
|
||||
; vcmpltss xmm0, xmm1, xmm2
|
||||
; movd r15d, xmm0
|
||||
; cmp r15d, 1
|
||||
; je >trap
|
||||
|
||||
// overflow
|
||||
; mov r15d, upper_bound as i32
|
||||
; movd xmm2, r15d
|
||||
; vcmpgtss xmm0, xmm1, xmm2
|
||||
; movd r15d, xmm0
|
||||
; cmp r15d, 1
|
||||
; je >trap
|
||||
|
||||
// NaN
|
||||
; vcmpeqss xmm0, xmm1, xmm1
|
||||
; movd r15d, xmm0
|
||||
; cmp r15d, 0
|
||||
; je >trap
|
||||
|
||||
; movq r15, xmm5
|
||||
; jmp >ok
|
||||
|
||||
; trap:
|
||||
; ud2
|
||||
|
||||
; ok:
|
||||
);
|
||||
}
|
||||
|
||||
fn emit_f64_int_conv_check(
|
||||
assembler: &mut Assembler,
|
||||
reg: Register,
|
||||
lower_bound: f64,
|
||||
upper_bound: f64,
|
||||
) {
|
||||
let lower_bound = f64::to_bits(lower_bound);
|
||||
let upper_bound = f64::to_bits(upper_bound);
|
||||
|
||||
dynasm!(
|
||||
assembler
|
||||
; movq xmm5, r15
|
||||
|
||||
// underflow
|
||||
; movq xmm1, Rq(reg as u8)
|
||||
; mov r15, QWORD lower_bound as i64
|
||||
; movq xmm2, r15
|
||||
; vcmpltsd xmm0, xmm1, xmm2
|
||||
; movd r15d, xmm0
|
||||
; cmp r15d, 1
|
||||
; je >trap
|
||||
|
||||
// overflow
|
||||
; mov r15, QWORD upper_bound as i64
|
||||
; movq xmm2, r15
|
||||
; vcmpgtsd xmm0, xmm1, xmm2
|
||||
; movd r15d, xmm0
|
||||
; cmp r15d, 1
|
||||
; je >trap
|
||||
|
||||
// NaN
|
||||
; vcmpeqsd xmm0, xmm1, xmm1
|
||||
; movd r15d, xmm0
|
||||
; cmp r15d, 0
|
||||
; je >trap
|
||||
|
||||
; movq r15, xmm5
|
||||
; jmp >ok
|
||||
|
||||
; trap:
|
||||
; ud2
|
||||
|
||||
; ok:
|
||||
);
|
||||
}
|
||||
|
||||
fn emit_native_call_trampoline<A: Copy + Sized, B: Copy + Sized>(
|
||||
assembler: &mut Assembler,
|
||||
target: unsafe extern "C" fn(
|
||||
@ -4137,11 +4247,17 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
WpType::F32
|
||||
)?;
|
||||
}
|
||||
Operator::I32TruncUF32 | Operator::I32TruncSF32 => {
|
||||
Operator::I32TruncUF32 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f32_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-1.0,
|
||||
4294967296.0,
|
||||
);
|
||||
dynasm!(
|
||||
assembler
|
||||
; movd xmm1, Rd(reg as u8)
|
||||
@ -4153,11 +4269,61 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
WpType::I32
|
||||
)?;
|
||||
}
|
||||
Operator::I64TruncUF32 | Operator::I64TruncSF32 => {
|
||||
Operator::I32TruncSF32 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f32_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-2147483904.0,
|
||||
2147483648.0
|
||||
);
|
||||
dynasm!(
|
||||
assembler
|
||||
; movd xmm1, Rd(reg as u8)
|
||||
; roundss xmm1, xmm1, 3
|
||||
; cvtss2si Rd(reg as u8), xmm1
|
||||
);
|
||||
},
|
||||
WpType::F32,
|
||||
WpType::I32
|
||||
)?;
|
||||
}
|
||||
Operator::I64TruncUF32 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f32_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-1.0,
|
||||
18446744073709551616.0,
|
||||
);
|
||||
dynasm!(
|
||||
assembler
|
||||
; movd xmm1, Rd(reg as u8)
|
||||
; roundss xmm1, xmm1, 3
|
||||
; cvtss2si Rq(reg as u8), xmm1
|
||||
);
|
||||
},
|
||||
WpType::F32,
|
||||
WpType::I64
|
||||
)?;
|
||||
}
|
||||
Operator::I64TruncSF32 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f32_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-9223373136366403584.0,
|
||||
9223372036854775808.0,
|
||||
);
|
||||
dynasm!(
|
||||
assembler
|
||||
; movd xmm1, Rd(reg as u8)
|
||||
@ -4514,11 +4680,18 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
WpType::F64
|
||||
)?;
|
||||
}
|
||||
Operator::I32TruncUF64 | Operator::I32TruncSF64 => {
|
||||
Operator::I32TruncUF64 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f64_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-1.0,
|
||||
4294967296.0,
|
||||
);
|
||||
|
||||
dynasm!(
|
||||
assembler
|
||||
; movq xmm1, Rq(reg as u8)
|
||||
@ -4530,11 +4703,64 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
WpType::I32
|
||||
)?;
|
||||
}
|
||||
Operator::I64TruncUF64 | Operator::I64TruncSF64 => {
|
||||
Operator::I32TruncSF64 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f64_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-2147483649.0,
|
||||
2147483648.0,
|
||||
);
|
||||
|
||||
dynasm!(
|
||||
assembler
|
||||
; movq xmm1, Rq(reg as u8)
|
||||
; roundsd xmm1, xmm1, 3
|
||||
; cvtsd2si Rd(reg as u8), xmm1
|
||||
);
|
||||
},
|
||||
WpType::F64,
|
||||
WpType::I32
|
||||
)?;
|
||||
}
|
||||
Operator::I64TruncUF64 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f64_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-1.0,
|
||||
18446744073709551616.0,
|
||||
);
|
||||
|
||||
dynasm!(
|
||||
assembler
|
||||
; movq xmm1, Rq(reg as u8)
|
||||
; roundsd xmm1, xmm1, 3
|
||||
; cvtsd2si Rq(reg as u8), xmm1
|
||||
);
|
||||
},
|
||||
WpType::F64,
|
||||
WpType::I64
|
||||
)?;
|
||||
}
|
||||
Operator::I64TruncSF64 => {
|
||||
Self::emit_unop(
|
||||
assembler,
|
||||
&mut self.value_stack,
|
||||
|assembler, value_stack, reg| {
|
||||
Self::emit_f64_int_conv_check(
|
||||
assembler,
|
||||
reg,
|
||||
-9223372036854777856.0,
|
||||
9223372036854775808.0,
|
||||
);
|
||||
|
||||
dynasm!(
|
||||
assembler
|
||||
; movq xmm1, Rq(reg as u8)
|
||||
@ -4553,7 +4779,8 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let mem_desc = &module_info.memories[local_mem_index];
|
||||
match mem_desc.memory_type() {
|
||||
MemoryType::Dynamic => self.native_trampolines.memory_size_dynamic_local,
|
||||
//MemoryType::Dynamic => self.native_trampolines.memory_size_dynamic_local,
|
||||
MemoryType::Dynamic => unimplemented!(),
|
||||
MemoryType::Static => self.native_trampolines.memory_size_static_local,
|
||||
MemoryType::SharedStatic => self.native_trampolines.memory_size_shared_local,
|
||||
}
|
||||
@ -4561,7 +4788,8 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
LocalOrImport::Import(import_mem_index) => {
|
||||
let mem_desc = &module_info.imported_memories[import_mem_index].1;
|
||||
match mem_desc.memory_type() {
|
||||
MemoryType::Dynamic => self.native_trampolines.memory_size_dynamic_import,
|
||||
//MemoryType::Dynamic => self.native_trampolines.memory_size_dynamic_import,
|
||||
MemoryType::Dynamic => unimplemented!(),
|
||||
MemoryType::Static => self.native_trampolines.memory_size_static_import,
|
||||
MemoryType::SharedStatic => self.native_trampolines.memory_size_shared_import,
|
||||
}
|
||||
@ -4581,7 +4809,8 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let mem_desc = &module_info.memories[local_mem_index];
|
||||
match mem_desc.memory_type() {
|
||||
MemoryType::Dynamic => self.native_trampolines.memory_grow_dynamic_local,
|
||||
//MemoryType::Dynamic => self.native_trampolines.memory_grow_dynamic_local,
|
||||
MemoryType::Dynamic => unimplemented!(),
|
||||
MemoryType::Static => self.native_trampolines.memory_grow_static_local,
|
||||
MemoryType::SharedStatic => self.native_trampolines.memory_grow_shared_local,
|
||||
}
|
||||
@ -4589,7 +4818,8 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
||||
LocalOrImport::Import(import_mem_index) => {
|
||||
let mem_desc = &module_info.imported_memories[import_mem_index].1;
|
||||
match mem_desc.memory_type() {
|
||||
MemoryType::Dynamic => self.native_trampolines.memory_grow_dynamic_import,
|
||||
//MemoryType::Dynamic => self.native_trampolines.memory_grow_dynamic_import,
|
||||
MemoryType::Dynamic => unimplemented!(),
|
||||
MemoryType::Static => self.native_trampolines.memory_grow_static_import,
|
||||
MemoryType::SharedStatic => self.native_trampolines.memory_grow_shared_import,
|
||||
}
|
||||
@ -4725,13 +4955,20 @@ unsafe extern "C" fn call_indirect(
|
||||
CallIndirectLocalOrImport::Import => &*(*(*vmctx).imported_tables),
|
||||
} ;
|
||||
if elem_index >= table.count as usize {
|
||||
panic!("element index out of bounds");
|
||||
eprintln!("element index out of bounds");
|
||||
unsafe { protect_unix::trigger_trap(); }
|
||||
}
|
||||
let anyfunc = &*(table.base as *mut vm::Anyfunc).offset(elem_index as isize);
|
||||
let ctx: &X64ExecutionContext =
|
||||
&*CURRENT_EXECUTION_CONTEXT.with(|x| *x.borrow().last().unwrap());
|
||||
|
||||
let func_index = anyfunc.func_index.unwrap();
|
||||
let func_index = match anyfunc.func_index {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
eprintln!("empty table entry");
|
||||
unsafe { protect_unix::trigger_trap(); }
|
||||
}
|
||||
};
|
||||
|
||||
/*println!(
|
||||
"SIG INDEX = {}, FUNC INDEX = {:?}, ELEM INDEX = {}",
|
||||
@ -4741,7 +4978,8 @@ unsafe extern "C" fn call_indirect(
|
||||
if ctx.signatures[SigIndex::new(sig_index)]
|
||||
!= ctx.signatures[ctx.function_signatures[func_index]]
|
||||
{
|
||||
panic!("signature mismatch");
|
||||
eprintln!("signature mismatch");
|
||||
unsafe { protect_unix::trigger_trap(); }
|
||||
}
|
||||
|
||||
let func = ctx.function_pointers[func_index.index() as usize].0;
|
||||
|
@ -1,5 +1,11 @@
|
||||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
#[cfg(not(any(
|
||||
all(target_os = "macos", target_arch = "x86_64"),
|
||||
all(target_os = "linux", target_arch = "x86_64"),
|
||||
)))]
|
||||
compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64");
|
||||
|
||||
#[macro_use]
|
||||
extern crate dynasmrt;
|
||||
|
||||
@ -15,6 +21,7 @@ mod codegen;
|
||||
mod codegen_x64;
|
||||
mod parse;
|
||||
mod stack;
|
||||
mod protect_unix;
|
||||
|
||||
use crate::codegen::{CodegenError, ModuleCodeGenerator};
|
||||
use crate::parse::LoadError;
|
||||
|
@ -18,6 +18,7 @@ use wasmparser::{
|
||||
BinaryReaderError, CodeSectionReader, Data, DataKind, Element, ElementKind, Export,
|
||||
ExternalKind, FuncType, Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator,
|
||||
SectionCode, Type as WpType,
|
||||
WasmDecoder,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -38,6 +39,30 @@ impl From<CodegenError> for LoadError {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(bytes: &[u8]) -> Result<(), LoadError> {
|
||||
let mut parser = wasmparser::ValidatingParser::new(
|
||||
bytes,
|
||||
Some(wasmparser::ValidatingParserConfig {
|
||||
operator_config: wasmparser::OperatorValidatorConfig {
|
||||
enable_threads: false,
|
||||
enable_reference_types: false,
|
||||
enable_simd: false,
|
||||
enable_bulk_memory: false,
|
||||
},
|
||||
mutable_global_imports: false,
|
||||
}),
|
||||
);
|
||||
|
||||
loop {
|
||||
let state = parser.read();
|
||||
match *state {
|
||||
wasmparser::ParserState::EndWasm => break Ok(()),
|
||||
wasmparser::ParserState::Error(err) => Err(LoadError::Parse(err))?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_module<
|
||||
MCG: ModuleCodeGenerator<FCG, PC, FR>,
|
||||
FCG: FunctionCodeGenerator,
|
||||
@ -48,6 +73,7 @@ pub fn read_module<
|
||||
backend: Backend,
|
||||
mcg: &mut MCG,
|
||||
) -> Result<ModuleInfo, LoadError> {
|
||||
validate(wasm)?;
|
||||
let mut info = ModuleInfo {
|
||||
memories: Map::new(),
|
||||
globals: Map::new(),
|
||||
@ -279,6 +305,7 @@ pub fn read_module<
|
||||
}
|
||||
.into());
|
||||
}
|
||||
mcg.check_precondition(&info)?;
|
||||
for i in 0..code_reader.get_count() {
|
||||
let item = code_reader.read()?;
|
||||
let mut fcg = mcg.next_function()?;
|
||||
|
202
lib/dynasm-backend/src/protect_unix.rs
Normal file
202
lib/dynasm-backend/src/protect_unix.rs
Normal file
@ -0,0 +1,202 @@
|
||||
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
||||
//! accesses that occur when runniing webassembly.
|
||||
//!
|
||||
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
||||
//!
|
||||
//! When a WebAssembly module triggers any traps, we perform recovery here.
|
||||
//!
|
||||
//! This module uses TLS (thread-local storage) to track recovery information. Since the four signals we're handling
|
||||
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
||||
//! unless you have memory unsafety elsewhere in your code.
|
||||
//!
|
||||
use libc::{c_int, c_void, siginfo_t};
|
||||
use nix::sys::signal::{
|
||||
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
||||
};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::ptr;
|
||||
use std::sync::Once;
|
||||
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
|
||||
|
||||
extern "C" fn signal_trap_handler(
|
||||
signum: ::nix::libc::c_int,
|
||||
siginfo: *mut siginfo_t,
|
||||
ucontext: *mut c_void,
|
||||
) {
|
||||
unsafe {
|
||||
do_unwind(signum, siginfo as _, ucontext);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn setjmp(env: *mut c_void) -> c_int;
|
||||
fn longjmp(env: *mut c_void, val: c_int) -> !;
|
||||
}
|
||||
|
||||
pub unsafe fn install_sighandler() {
|
||||
let sa = SigAction::new(
|
||||
SigHandler::SigAction(signal_trap_handler),
|
||||
SaFlags::SA_ONSTACK,
|
||||
SigSet::empty(),
|
||||
);
|
||||
sigaction(SIGFPE, &sa).unwrap();
|
||||
sigaction(SIGILL, &sa).unwrap();
|
||||
sigaction(SIGSEGV, &sa).unwrap();
|
||||
sigaction(SIGBUS, &sa).unwrap();
|
||||
}
|
||||
|
||||
const SETJMP_BUFFER_LEN: usize = 27;
|
||||
pub static SIGHANDLER_INIT: Once = Once::new();
|
||||
|
||||
thread_local! {
|
||||
pub static SETJMP_BUFFER: UnsafeCell<[c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]);
|
||||
pub static CAUGHT_ADDRESSES: Cell<(*const c_void, *const c_void)> = Cell::new((ptr::null(), ptr::null()));
|
||||
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
|
||||
}
|
||||
|
||||
pub unsafe fn trigger_trap() -> ! {
|
||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||
|
||||
longjmp(jmp_buf as *mut c_void, 0)
|
||||
}
|
||||
|
||||
pub fn call_protected<T>(f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
||||
unsafe {
|
||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||
let prev_jmp_buf = *jmp_buf;
|
||||
|
||||
SIGHANDLER_INIT.call_once(|| {
|
||||
install_sighandler();
|
||||
});
|
||||
|
||||
let signum = setjmp(jmp_buf as *mut _);
|
||||
if signum != 0 {
|
||||
*jmp_buf = prev_jmp_buf;
|
||||
|
||||
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
||||
|
||||
let signal = match Signal::from_c_int(signum) {
|
||||
Ok(SIGFPE) => "floating-point exception",
|
||||
Ok(SIGILL) => "illegal instruction",
|
||||
Ok(SIGSEGV) => "segmentation violation",
|
||||
Ok(SIGBUS) => "bus error",
|
||||
Err(_) => "error while getting the Signal",
|
||||
_ => "unkown trapped signal",
|
||||
};
|
||||
// When the trap-handler is fully implemented, this will return more information.
|
||||
Err(RuntimeError::Trap {
|
||||
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
|
||||
}
|
||||
.into())
|
||||
} else {
|
||||
let ret = f(); // TODO: Switch stack?
|
||||
*jmp_buf = prev_jmp_buf;
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwinds to last protected_call.
|
||||
pub unsafe fn do_unwind(signum: i32, siginfo: *const c_void, ucontext: *const c_void) -> ! {
|
||||
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
|
||||
// itself, accessing TLS here is safe. In case any other code calls this, it often indicates a memory safety bug and you should
|
||||
// temporarily disable the signal handlers to debug it.
|
||||
|
||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||
if *jmp_buf == [0; SETJMP_BUFFER_LEN] {
|
||||
::std::process::abort();
|
||||
}
|
||||
|
||||
CAUGHT_ADDRESSES.with(|cell| cell.set(get_faulting_addr_and_ip(siginfo, ucontext)));
|
||||
|
||||
longjmp(jmp_buf as *mut ::nix::libc::c_void, signum)
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
unsafe fn get_faulting_addr_and_ip(
|
||||
siginfo: *const c_void,
|
||||
ucontext: *const c_void,
|
||||
) -> (*const c_void, *const c_void) {
|
||||
use libc::{ucontext_t, RIP};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(C)]
|
||||
struct siginfo_t {
|
||||
si_signo: i32,
|
||||
si_errno: i32,
|
||||
si_code: i32,
|
||||
si_addr: u64,
|
||||
// ...
|
||||
}
|
||||
|
||||
let siginfo = siginfo as *const siginfo_t;
|
||||
let si_addr = (*siginfo).si_addr;
|
||||
|
||||
let ucontext = ucontext as *const ucontext_t;
|
||||
let rip = (*ucontext).uc_mcontext.gregs[RIP as usize];
|
||||
|
||||
(si_addr as _, rip as _)
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
unsafe fn get_faulting_addr_and_ip(
|
||||
siginfo: *const c_void,
|
||||
ucontext: *const c_void,
|
||||
) -> (*const c_void, *const c_void) {
|
||||
#[allow(dead_code)]
|
||||
#[repr(C)]
|
||||
struct ucontext_t {
|
||||
uc_onstack: u32,
|
||||
uc_sigmask: u32,
|
||||
uc_stack: libc::stack_t,
|
||||
uc_link: *const ucontext_t,
|
||||
uc_mcsize: u64,
|
||||
uc_mcontext: *const mcontext_t,
|
||||
}
|
||||
#[repr(C)]
|
||||
struct exception_state {
|
||||
trapno: u16,
|
||||
cpu: u16,
|
||||
err: u32,
|
||||
faultvaddr: u64,
|
||||
}
|
||||
#[repr(C)]
|
||||
struct regs {
|
||||
rax: u64,
|
||||
rbx: u64,
|
||||
rcx: u64,
|
||||
rdx: u64,
|
||||
rdi: u64,
|
||||
rsi: u64,
|
||||
rbp: u64,
|
||||
rsp: u64,
|
||||
r8: u64,
|
||||
r9: u64,
|
||||
r10: u64,
|
||||
r11: u64,
|
||||
r12: u64,
|
||||
r13: u64,
|
||||
r14: u64,
|
||||
r15: u64,
|
||||
rip: u64,
|
||||
rflags: u64,
|
||||
cs: u64,
|
||||
fs: u64,
|
||||
gs: u64,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[repr(C)]
|
||||
struct mcontext_t {
|
||||
es: exception_state,
|
||||
ss: regs,
|
||||
// ...
|
||||
}
|
||||
|
||||
let siginfo = siginfo as *const siginfo_t;
|
||||
let si_addr = (*siginfo).si_addr;
|
||||
|
||||
let ucontext = ucontext as *const ucontext_t;
|
||||
let rip = (*(*ucontext).uc_mcontext).ss.rip;
|
||||
|
||||
(si_addr, rip as _)
|
||||
}
|
@ -251,8 +251,8 @@ impl MemoryDescriptor {
|
||||
pub fn memory_type(self) -> MemoryType {
|
||||
match (self.maximum.is_some(), self.shared) {
|
||||
(true, true) => MemoryType::SharedStatic,
|
||||
(true, false) => MemoryType::Static,
|
||||
(false, false) => MemoryType::Dynamic,
|
||||
(true, false) | (false, false) => MemoryType::Static,
|
||||
//(false, false) => MemoryType::Dynamic,
|
||||
(false, true) => panic!("shared memory without a max is not allowed"),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user