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

@ -0,0 +1,11 @@
[package]
name = "wasmer-middleware-common"
version = "0.3.0"
repository = "https://github.com/wasmerio/wasmer"
description = "Wasmer runtime common middlewares"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }

View File

@ -0,0 +1,27 @@
use wasmer_runtime_core::{
codegen::{Event, EventSink, FunctionMiddleware, InternalEvent},
module::ModuleInfo,
};
pub struct CallTrace;
impl FunctionMiddleware for CallTrace {
type Error = String;
fn feed_event<'a, 'b: 'a>(
&mut self,
op: Event<'a, 'b>,
module_info: &ModuleInfo,
sink: &mut EventSink<'a, 'b>,
) -> Result<(), Self::Error> {
match op {
Event::Internal(InternalEvent::FunctionBegin(id)) => {
sink.push(Event::Internal(InternalEvent::Bkpt(Box::new(move |_| {
println!("func ({})", id);
}))))
}
_ => {}
}
sink.push(op);
Ok(())
}
}

View File

@ -0,0 +1,9 @@
pub mod call_trace;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

View File

@ -1,30 +1,33 @@
use crate::{ use crate::{
backend::RunnableModule, backend::RunnableModule,
structures::Map,
types::{FuncIndex, FuncSig, SigIndex},
backend::{sys::Memory, Backend, CacheGen, Compiler, CompilerConfig, Token}, backend::{sys::Memory, Backend, CacheGen, Compiler, CompilerConfig, Token},
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
error::{CompileError, CompileResult}, error::{CompileError, CompileResult},
module::{ModuleInfo, ModuleInner}, module::{ModuleInfo, ModuleInner},
parse::LoadError, parse::LoadError,
structures::Map,
types::{FuncIndex, FuncSig, SigIndex},
}; };
use wasmparser::{Operator, Type as WpType};
use std::fmt::Debug;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use wasmparser::{Operator, Type as WpType};
pub enum Event<'a, 'b> { pub enum Event<'a, 'b> {
Internal(InternalEvent), Internal(InternalEvent),
Wasm(&'b Operator<'a>), Wasm(&'b Operator<'a>),
} }
#[derive(Copy, Clone, Debug)]
pub enum InternalEvent { pub enum InternalEvent {
FunctionBegin, FunctionBegin(u32),
FunctionEnd, FunctionEnd,
Trace, Bkpt(Box<Fn(BkptInfo) + Send + Sync + 'static>),
SetInternal(u32),
GetInternal(u32),
} }
pub struct BkptInfo {}
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> { pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
fn new() -> Self; fn new() -> Self;
fn backend_id() -> Backend; fn backend_id() -> Backend;
@ -36,10 +39,7 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>; fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
/// Sets function signatures. /// Sets function signatures.
fn feed_function_signatures( fn feed_function_signatures(&mut self, assoc: Map<FuncIndex, SigIndex>) -> Result<(), E>;
&mut self,
assoc: Map<FuncIndex, SigIndex>,
) -> Result<(), E>;
/// Adds an import function. /// Adds an import function.
fn feed_import_function(&mut self) -> Result<(), E>; fn feed_import_function(&mut self) -> Result<(), E>;
@ -72,23 +72,25 @@ pub struct SimpleStreamingCompilerGen<
} }
impl< impl<
MCG: ModuleCodeGenerator<FCG, RM, E>, MCG: ModuleCodeGenerator<FCG, RM, E>,
FCG: FunctionCodeGenerator<E>, FCG: FunctionCodeGenerator<E>,
RM: RunnableModule + 'static, RM: RunnableModule + 'static,
E: Debug, E: Debug,
> SimpleStreamingCompilerGen<MCG, FCG, RM, E> { > SimpleStreamingCompilerGen<MCG, FCG, RM, E>
{
pub fn new() -> StreamingCompiler<MCG, FCG, RM, E, impl Fn() -> MiddlewareChain> { pub fn new() -> StreamingCompiler<MCG, FCG, RM, E, impl Fn() -> MiddlewareChain> {
StreamingCompiler::new(|| MiddlewareChain::new()) StreamingCompiler::new(|| MiddlewareChain::new())
} }
} }
impl< impl<
MCG: ModuleCodeGenerator<FCG, RM, E>, MCG: ModuleCodeGenerator<FCG, RM, E>,
FCG: FunctionCodeGenerator<E>, FCG: FunctionCodeGenerator<E>,
RM: RunnableModule + 'static, RM: RunnableModule + 'static,
E: Debug, E: Debug,
CGEN: Fn() -> MiddlewareChain, CGEN: Fn() -> MiddlewareChain,
> StreamingCompiler<MCG, FCG, RM, E, CGEN> { > StreamingCompiler<MCG, FCG, RM, E, CGEN>
{
pub fn new(chain_gen: CGEN) -> Self { pub fn new(chain_gen: CGEN) -> Self {
Self { Self {
middleware_chain_generator: chain_gen, middleware_chain_generator: chain_gen,
@ -101,12 +103,13 @@ impl<
} }
impl< impl<
MCG: ModuleCodeGenerator<FCG, RM, E>, MCG: ModuleCodeGenerator<FCG, RM, E>,
FCG: FunctionCodeGenerator<E>, FCG: FunctionCodeGenerator<E>,
RM: RunnableModule + 'static, RM: RunnableModule + 'static,
E: Debug, E: Debug,
CGEN: Fn() -> MiddlewareChain, CGEN: Fn() -> MiddlewareChain,
>Compiler for StreamingCompiler<MCG, FCG, RM, E, CGEN> { > Compiler for StreamingCompiler<MCG, FCG, RM, E, CGEN>
{
fn compile( fn compile(
&self, &self,
wasm: &[u8], wasm: &[u8],
@ -124,10 +127,18 @@ impl<
let mut mcg = MCG::new(); let mut mcg = MCG::new();
let mut chain = (self.middleware_chain_generator)(); let mut chain = (self.middleware_chain_generator)();
let info = crate::parse::read_module(wasm, MCG::backend_id(), &mut mcg, &mut chain, &compiler_config)?; let info = crate::parse::read_module(
let exec_context = mcg.finalize(&info).map_err(|x| CompileError::InternalError { wasm,
msg: format!("{:?}", x), MCG::backend_id(),
})?; &mut mcg,
&mut chain,
&compiler_config,
)?;
let exec_context = mcg
.finalize(&info)
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
Ok(ModuleInner { Ok(ModuleInner {
cache_gen: Box::new(Placeholder), cache_gen: Box::new(Placeholder),
runnable_module: Box::new(exec_context), runnable_module: Box::new(exec_context),
@ -143,7 +154,7 @@ impl<
} }
pub struct EventSink<'a, 'b> { pub struct EventSink<'a, 'b> {
buffer: SmallVec<[Event<'a, 'b>; 2]> buffer: SmallVec<[Event<'a, 'b>; 2]>,
} }
impl<'a, 'b> EventSink<'a, 'b> { impl<'a, 'b> EventSink<'a, 'b> {
@ -158,16 +169,19 @@ pub struct MiddlewareChain {
impl MiddlewareChain { impl MiddlewareChain {
pub fn new() -> MiddlewareChain { pub fn new() -> MiddlewareChain {
MiddlewareChain { MiddlewareChain { chain: vec![] }
chain: vec! [],
}
} }
pub fn push<M: FunctionMiddleware + 'static>(&mut self, m: M) { pub fn push<M: FunctionMiddleware + 'static>(&mut self, m: M) {
self.chain.push(Box::new(m)); self.chain.push(Box::new(m));
} }
pub(crate) fn run<E: Debug, FCG: FunctionCodeGenerator<E>>(&mut self, fcg: Option<&mut FCG>, ev: Event, module_info: &ModuleInfo) -> Result<(), String> { pub(crate) fn run<E: Debug, FCG: FunctionCodeGenerator<E>>(
&mut self,
fcg: Option<&mut FCG>,
ev: Event,
module_info: &ModuleInfo,
) -> Result<(), String> {
let mut sink = EventSink { let mut sink = EventSink {
buffer: SmallVec::new(), buffer: SmallVec::new(),
}; };
@ -180,7 +194,8 @@ impl MiddlewareChain {
} }
if let Some(fcg) = fcg { if let Some(fcg) = fcg {
for ev in sink.buffer { for ev in sink.buffer {
fcg.feed_event(ev, module_info).map_err(|x| format!("{:?}", x))?; fcg.feed_event(ev, module_info)
.map_err(|x| format!("{:?}", x))?;
} }
} }
@ -190,31 +205,32 @@ impl MiddlewareChain {
pub trait FunctionMiddleware { pub trait FunctionMiddleware {
type Error: Debug; type Error: Debug;
fn feed_event( fn feed_event<'a, 'b: 'a>(
&mut self, &mut self,
op: Event, op: Event<'a, 'b>,
module_info: &ModuleInfo, module_info: &ModuleInfo,
sink: &mut EventSink, sink: &mut EventSink<'a, 'b>,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
} }
pub(crate) trait GenericFunctionMiddleware { pub(crate) trait GenericFunctionMiddleware {
fn feed_event( fn feed_event<'a, 'b: 'a>(
&mut self, &mut self,
op: Event, op: Event<'a, 'b>,
module_info: &ModuleInfo, module_info: &ModuleInfo,
sink: &mut EventSink, sink: &mut EventSink<'a, 'b>,
) -> Result<(), String>; ) -> Result<(), String>;
} }
impl<E: Debug, T: FunctionMiddleware<Error = E>> GenericFunctionMiddleware for T { impl<E: Debug, T: FunctionMiddleware<Error = E>> GenericFunctionMiddleware for T {
fn feed_event( fn feed_event<'a, 'b: 'a>(
&mut self, &mut self,
op: Event, op: Event<'a, 'b>,
module_info: &ModuleInfo, module_info: &ModuleInfo,
sink: &mut EventSink, sink: &mut EventSink<'a, 'b>,
) -> Result<(), String> { ) -> Result<(), String> {
<Self as FunctionMiddleware>::feed_event(self, op, module_info, sink).map_err(|x| format!("{:?}", x)) <Self as FunctionMiddleware>::feed_event(self, op, module_info, sink)
.map_err(|x| format!("{:?}", x))
} }
} }

View File

@ -14,6 +14,7 @@ pub mod backend;
mod backing; mod backing;
pub mod cache; pub mod cache;
pub mod codegen;
pub mod error; pub mod error;
pub mod export; pub mod export;
pub mod global; pub mod global;
@ -21,6 +22,7 @@ pub mod import;
pub mod instance; pub mod instance;
pub mod memory; pub mod memory;
pub mod module; pub mod module;
pub mod parse;
mod sig_registry; mod sig_registry;
pub mod structures; pub mod structures;
mod sys; mod sys;
@ -31,8 +33,6 @@ pub mod units;
pub mod vm; pub mod vm;
#[doc(hidden)] #[doc(hidden)]
pub mod vmcalls; pub mod vmcalls;
pub mod codegen;
pub mod parse;
use self::error::CompileResult; use self::error::CompileResult;
#[doc(inline)] #[doc(inline)]

View File

@ -1,7 +1,7 @@
use crate::codegen::*; use crate::codegen::*;
use hashbrown::HashMap;
use crate::{ use crate::{
backend::{Backend, CompilerConfig, RunnableModule}, backend::{Backend, CompilerConfig, RunnableModule},
error::CompileError,
module::{ module::{
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder, DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
TableInitializer, TableInitializer,
@ -13,14 +13,14 @@ use crate::{
TableIndex, Type, Value, TableIndex, Type, Value,
}, },
units::Pages, units::Pages,
error::CompileError,
}; };
use hashbrown::HashMap;
use std::fmt::Debug;
use wasmparser::{ use wasmparser::{
BinaryReaderError, Data, DataKind, Element, ElementKind, Export, ExternalKind, FuncType, BinaryReaderError, Data, DataKind, Element, ElementKind, Export, ExternalKind, FuncType,
Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator, SectionCode, Type as WpType, Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator, SectionCode, Type as WpType,
WasmDecoder, WasmDecoder,
}; };
use std::fmt::Debug;
#[derive(Debug)] #[derive(Debug)]
pub enum LoadError { pub enum LoadError {
@ -122,7 +122,8 @@ pub fn read_module<
let sigindex = SigIndex::new(sigindex as usize); let sigindex = SigIndex::new(sigindex as usize);
info.imported_functions.push(import_name); info.imported_functions.push(import_name);
info.func_assoc.push(sigindex); info.func_assoc.push(sigindex);
mcg.feed_import_function().map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; mcg.feed_import_function()
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
ImportSectionEntryType::Table(table_ty) => { ImportSectionEntryType::Table(table_ty) => {
assert_eq!(table_ty.element_type, WpType::AnyFunc); assert_eq!(table_ty.element_type, WpType::AnyFunc);
@ -192,13 +193,24 @@ pub fn read_module<
if func_count == 0 { if func_count == 0 {
info.namespace_table = namespace_builder.take().unwrap().finish(); info.namespace_table = namespace_builder.take().unwrap().finish();
info.name_table = name_builder.take().unwrap().finish(); info.name_table = name_builder.take().unwrap().finish();
mcg.feed_signatures(info.signatures.clone()).map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; mcg.feed_signatures(info.signatures.clone())
mcg.feed_function_signatures(info.func_assoc.clone()).map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
mcg.check_precondition(&info).map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; mcg.feed_function_signatures(info.func_assoc.clone())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
mcg.check_precondition(&info)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
let fcg = mcg.next_function().map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; let fcg = mcg
middlewares.run(Some(fcg), Event::Internal(InternalEvent::FunctionBegin), &info).map_err(|x| LoadError::Codegen(x))?; .next_function()
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
middlewares
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
&info,
)
.map_err(|x| LoadError::Codegen(x))?;
let sig = info let sig = info
.signatures .signatures
@ -210,10 +222,12 @@ pub fn read_module<
) )
.unwrap(); .unwrap();
for ret in sig.returns() { for ret in sig.returns() {
fcg.feed_return(type_to_wp_type(*ret)).map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; fcg.feed_return(type_to_wp_type(*ret))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
for param in sig.params() { for param in sig.params() {
fcg.feed_param(type_to_wp_type(*param)).map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; fcg.feed_param(type_to_wp_type(*param))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
let mut body_begun = false; let mut body_begun = false;
@ -224,22 +238,33 @@ pub fn read_module<
ParserState::Error(err) => return Err(LoadError::Parse(err)), ParserState::Error(err) => return Err(LoadError::Parse(err)),
ParserState::FunctionBodyLocals { ref locals } => { ParserState::FunctionBodyLocals { ref locals } => {
for &(count, ty) in locals.iter() { for &(count, ty) in locals.iter() {
fcg.feed_local(ty, count as usize).map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; fcg.feed_local(ty, count as usize)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
} }
ParserState::CodeOperator(ref op) => { ParserState::CodeOperator(ref op) => {
if !body_begun { if !body_begun {
body_begun = true; body_begun = true;
fcg.begin_body().map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; fcg.begin_body()
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
middlewares.run(Some(fcg), Event::Wasm(op), &info).map_err(|x| LoadError::Codegen(x))?; middlewares
.run(Some(fcg), Event::Wasm(op), &info)
.map_err(|x| LoadError::Codegen(x))?;
} }
ParserState::EndFunctionBody => break, ParserState::EndFunctionBody => break,
_ => unreachable!(), _ => unreachable!(),
} }
} }
middlewares.run(Some(fcg), Event::Internal(InternalEvent::FunctionEnd), &info).map_err(|x| LoadError::Codegen(x))?; middlewares
fcg.finalize().map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; .run(
Some(fcg),
Event::Internal(InternalEvent::FunctionEnd),
&info,
)
.map_err(|x| LoadError::Codegen(x))?;
fcg.finalize()
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
} }
ParserState::BeginActiveElementSectionEntry(table_index) => { ParserState::BeginActiveElementSectionEntry(table_index) => {
let table_index = TableIndex::new(table_index as usize); let table_index = TableIndex::new(table_index as usize);

View File

@ -22,7 +22,7 @@ pub struct Ctx {
local_backing: *mut LocalBacking, local_backing: *mut LocalBacking,
import_backing: *mut ImportBacking, import_backing: *mut ImportBacking,
pub(crate) module: *const ModuleInner, pub module: *const ModuleInner,
pub data: *mut c_void, pub data: *mut c_void,
pub data_finalizer: Option<fn(data: *mut c_void)>, pub data_finalizer: Option<fn(data: *mut c_void)>,

View File

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

View File

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

View File

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

View File

@ -12,11 +12,15 @@
use libc::{c_int, c_void, siginfo_t}; use libc::{c_int, c_void, siginfo_t};
use nix::sys::signal::{ use nix::sys::signal::{
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV, sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
SIGTRAP,
}; };
use std::any::Any; use std::any::Any;
use std::cell::{Cell, UnsafeCell}; use std::cell::{Cell, RefCell, UnsafeCell};
use std::collections::HashMap;
use std::ptr; use std::ptr;
use std::sync::Arc;
use std::sync::Once; use std::sync::Once;
use wasmer_runtime_core::codegen::BkptInfo;
use wasmer_runtime_core::typed_func::WasmTrapInfo; use wasmer_runtime_core::typed_func::WasmTrapInfo;
extern "C" fn signal_trap_handler( extern "C" fn signal_trap_handler(
@ -25,6 +29,20 @@ extern "C" fn signal_trap_handler(
ucontext: *mut c_void, ucontext: *mut c_void,
) { ) {
unsafe { 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); do_unwind(signum, siginfo as _, ucontext);
} }
} }
@ -44,6 +62,7 @@ pub unsafe fn install_sighandler() {
sigaction(SIGILL, &sa).unwrap(); sigaction(SIGILL, &sa).unwrap();
sigaction(SIGSEGV, &sa).unwrap(); sigaction(SIGSEGV, &sa).unwrap();
sigaction(SIGBUS, &sa).unwrap(); sigaction(SIGBUS, &sa).unwrap();
sigaction(SIGTRAP, &sa).unwrap();
} }
const SETJMP_BUFFER_LEN: usize = 27; 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 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 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 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() -> ! { pub unsafe fn trigger_trap() -> ! {