Finished middleware impl and made a CallTrace middleware

This commit is contained in:
losfair
2019-04-27 16:31:47 +08:00
parent eca8ccdbd4
commit 2262c8a6da
11 changed files with 266 additions and 109 deletions

View File

@ -11,6 +11,7 @@ use std::ptr::NonNull;
use std::{any::Any, collections::HashMap, sync::Arc};
use wasmer_runtime_core::{
backend::{Backend, RunnableModule},
codegen::*,
memory::MemoryType,
module::ModuleInfo,
structures::{Map, TypedIndex},
@ -21,7 +22,6 @@ use wasmer_runtime_core::{
},
vm::{self, LocalGlobal, LocalMemory, LocalTable},
vmcalls,
codegen::*,
};
use wasmparser::{Operator, Type as WpType};
@ -135,6 +135,7 @@ pub struct X64FunctionCode {
assembler: Option<Assembler>,
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
br_table_data: Option<Vec<Vec<usize>>>,
breakpoints: Option<HashMap<AssemblyOffset, Box<Fn(BkptInfo) + Send + Sync + 'static>>>,
returns: SmallVec<[WpType; 1]>,
locals: Vec<Location>,
num_params: usize,
@ -160,6 +161,7 @@ pub struct X64ExecutionContext {
function_pointers: Vec<FuncPtr>,
signatures: Arc<Map<SigIndex, FuncSig>>,
_br_table_data: Vec<Vec<usize>>,
breakpoints: Arc<HashMap<usize, Box<Fn(BkptInfo) + Send + Sync + 'static>>>,
func_import_count: usize,
}
@ -209,12 +211,18 @@ impl RunnableModule for X64ExecutionContext {
user_error: *mut Option<Box<dyn Any>>,
num_params_plus_one: Option<NonNull<c_void>>,
) -> bool {
let rm: &Box<dyn RunnableModule> = &unsafe { &*(*ctx).module }.runnable_module;
let execution_context = unsafe {
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm)
};
let args = ::std::slice::from_raw_parts(
args,
num_params_plus_one.unwrap().as_ptr() as usize - 1,
);
let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect();
match protect_unix::call_protected(|| {
protect_unix::BKPT_MAP
.with(|x| x.borrow_mut().push(execution_context.breakpoints.clone()));
let ret = match protect_unix::call_protected(|| {
CONSTRUCT_STACK_AND_CALL_WASM(
args_reverse.as_ptr(),
args_reverse.as_ptr().offset(args_reverse.len() as isize),
@ -235,7 +243,9 @@ impl RunnableModule for X64ExecutionContext {
}
false
}
}
};
protect_unix::BKPT_MAP.with(|x| x.borrow_mut().pop().unwrap());
ret
}
unsafe extern "C" fn dummy_trampoline(
@ -267,7 +277,9 @@ pub struct CodegenError {
pub message: &'static str,
}
impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError> for X64ModuleCodeGenerator {
impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
for X64ModuleCodeGenerator
{
fn new() -> X64ModuleCodeGenerator {
X64ModuleCodeGenerator {
functions: vec![],
@ -288,18 +300,21 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError> for
}
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) => (
x.assembler.take().unwrap(),
x.function_labels.take().unwrap(),
x.br_table_data.take().unwrap(),
),
None => (
self.assembler.take().unwrap(),
self.function_labels.take().unwrap(),
vec![],
),
};
let (mut assembler, mut function_labels, br_table_data, breakpoints) =
match self.functions.last_mut() {
Some(x) => (
x.assembler.take().unwrap(),
x.function_labels.take().unwrap(),
x.br_table_data.take().unwrap(),
x.breakpoints.take().unwrap(),
),
None => (
self.assembler.take().unwrap(),
self.function_labels.take().unwrap(),
vec![],
HashMap::new(),
),
};
let begin_offset = assembler.offset();
let begin_label_info = function_labels
.entry(self.functions.len() + self.func_import_count)
@ -320,6 +335,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError> for
assembler: Some(assembler),
function_labels: Some(function_labels),
br_table_data: Some(br_table_data),
breakpoints: Some(breakpoints),
returns: smallvec![],
locals: vec![],
num_params: 0,
@ -334,8 +350,12 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError> for
}
fn finalize(mut self, _: &ModuleInfo) -> Result<X64ExecutionContext, CodegenError> {
let (assembler, mut br_table_data) = match self.functions.last_mut() {
Some(x) => (x.assembler.take().unwrap(), x.br_table_data.take().unwrap()),
let (assembler, mut br_table_data, breakpoints) = match self.functions.last_mut() {
Some(x) => (
x.assembler.take().unwrap(),
x.br_table_data.take().unwrap(),
x.breakpoints.take().unwrap(),
),
None => {
return Err(CodegenError {
message: "no function",
@ -377,11 +397,19 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError> for
out_labels.push(FuncPtr(output.ptr(*offset) as _));
}
let breakpoints: Arc<HashMap<_, _>> = Arc::new(
breakpoints
.into_iter()
.map(|(offset, f)| (output.ptr(offset) as usize, f))
.collect(),
);
Ok(X64ExecutionContext {
code: output,
functions: self.functions,
signatures: self.signatures.as_ref().unwrap().clone(),
_br_table_data: br_table_data,
breakpoints: breakpoints,
func_import_count: self.func_import_count,
function_pointers: out_labels,
})
@ -1385,35 +1413,32 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
}
fn feed_event(&mut self, ev: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> {
let op = match ev {
Event::Wasm(x) => x,
Event::Internal(x) => {
return Ok(());
}
};
//println!("{:?} {}", op, self.value_stack.len());
let was_unreachable;
if self.unreachable_depth > 0 {
was_unreachable = true;
match *op {
Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => {
self.unreachable_depth += 1;
}
Operator::End => {
self.unreachable_depth -= 1;
}
Operator::Else => {
// We are in a reachable true branch
if self.unreachable_depth == 1 {
if let Some(IfElseState::If(_)) =
self.control_stack.last().map(|x| x.if_else)
{
self.unreachable_depth -= 1;
if let Event::Wasm(op) = ev {
match *op {
Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => {
self.unreachable_depth += 1;
}
Operator::End => {
self.unreachable_depth -= 1;
}
Operator::Else => {
// We are in a reachable true branch
if self.unreachable_depth == 1 {
if let Some(IfElseState::If(_)) =
self.control_stack.last().map(|x| x.if_else)
{
self.unreachable_depth -= 1;
}
}
}
_ => {}
}
_ => {}
}
if self.unreachable_depth > 0 {
return Ok(());
@ -1423,6 +1448,24 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
}
let a = self.assembler.as_mut().unwrap();
let op = match ev {
Event::Wasm(x) => x,
Event::Internal(x) => {
match x {
InternalEvent::Bkpt(callback) => {
a.emit_bkpt();
self.breakpoints
.as_mut()
.unwrap()
.insert(a.get_offset(), callback);
}
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {}
_ => unimplemented!(),
}
return Ok(());
}
};
match *op {
Operator::GetGlobal { global_index } => {
let global_index = global_index as usize;

View File

@ -194,6 +194,8 @@ pub trait Emitter {
fn emit_ret(&mut self);
fn emit_call_label(&mut self, label: Self::Label);
fn emit_call_location(&mut self, loc: Location);
fn emit_bkpt(&mut self);
}
macro_rules! unop_gpr {
@ -947,4 +949,8 @@ impl Emitter for Assembler {
_ => unreachable!(),
}
}
fn emit_bkpt(&mut self) {
dynasm!(self ; int 0x3);
}
}

View File

@ -23,8 +23,8 @@ mod emitter_x64;
mod machine;
mod protect_unix;
pub use codegen_x64::X64ModuleCodeGenerator as ModuleCodeGenerator;
pub use codegen_x64::X64FunctionCode as FunctionCodeGenerator;
pub use codegen_x64::X64ModuleCodeGenerator as ModuleCodeGenerator;
use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen;
pub type SinglePassCompiler = SimpleStreamingCompilerGen<
@ -32,4 +32,4 @@ pub type SinglePassCompiler = SimpleStreamingCompilerGen<
codegen_x64::X64FunctionCode,
codegen_x64::X64ExecutionContext,
codegen_x64::CodegenError,
>;
>;

View File

@ -12,11 +12,15 @@
use libc::{c_int, c_void, siginfo_t};
use nix::sys::signal::{
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
SIGTRAP,
};
use std::any::Any;
use std::cell::{Cell, UnsafeCell};
use std::cell::{Cell, RefCell, UnsafeCell};
use std::collections::HashMap;
use std::ptr;
use std::sync::Arc;
use std::sync::Once;
use wasmer_runtime_core::codegen::BkptInfo;
use wasmer_runtime_core::typed_func::WasmTrapInfo;
extern "C" fn signal_trap_handler(
@ -25,6 +29,20 @@ extern "C" fn signal_trap_handler(
ucontext: *mut c_void,
) {
unsafe {
match Signal::from_c_int(signum) {
Ok(SIGTRAP) => {
let (_, ip) = get_faulting_addr_and_ip(siginfo as _, ucontext);
let bkpt_map = BKPT_MAP.with(|x| x.borrow().last().map(|x| x.clone()));
if let Some(bkpt_map) = bkpt_map {
if let Some(ref x) = bkpt_map.get(&(ip as usize)) {
(x)(BkptInfo {});
return;
}
}
}
_ => {}
}
do_unwind(signum, siginfo as _, ucontext);
}
}
@ -44,6 +62,7 @@ pub unsafe fn install_sighandler() {
sigaction(SIGILL, &sa).unwrap();
sigaction(SIGSEGV, &sa).unwrap();
sigaction(SIGBUS, &sa).unwrap();
sigaction(SIGTRAP, &sa).unwrap();
}
const SETJMP_BUFFER_LEN: usize = 27;
@ -54,6 +73,7 @@ thread_local! {
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 static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
pub static BKPT_MAP: RefCell<Vec<Arc<HashMap<usize, Box<Fn(BkptInfo) + Send + Sync + 'static>>>>> = RefCell::new(Vec::new());
}
pub unsafe fn trigger_trap() -> ! {