Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task/calls (#110) #111

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion docs/src/devs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Below is an example `.wast` test:
```webassembly
;; Test `wasm:opcode:call` event

;; @instrument
(module
;; Auxiliary definitions
(func $other (param i32) (result i32) (local.get 1))
Expand All @@ -45,8 +46,51 @@ Below is an example `.wast` test:
(assert_return (invoke "instrument_me") (i32.const 1)) ;; will be run with the above WHAMM instrumentation
```

Below is an example `.wast` test using imports:
```webassembly
(module
(func (export "dummy") (param i32) (result i32)
local.get 0
)
)

(register "test")

;; @instrument
(module
;; Imports
(type (;0;) (func (param i32) (result i32)))
(import "test" "dummy" (func $dummy (type 0)))

;; Globals
(global $var (mut i32) (i32.const 0))

;; Global getters
(func $get_global_var (result i32)
(global.get $var)
)

;; Test case functions
(func $foo
(call $dummy (i32.const 0))
global.set $var
)

(start $foo)
(export "foo" (func $foo))
(export "get_global_var" (func $get_global_var))
(memory (;0;) 1)
)

;; WHAMM --> i32 count; wasm:opcode:call:alt / arg0 == 0 / { count = 5; return 1; }
(assert_return (invoke "get_global_var") (i32.const 1)) ;; alt, so global should be return value
(assert_return (invoke "get_count") (i32.const 5))
```

There are several conventions to follow when writing `.wast` test cases for `whamm`.
1. Only one `module` per `.wast` file.
1. Only one `module`-to-instrument per `.wast` file.
- The test setup goes at the top (which can include multiple modules when considering testing imports).
- The `module`-to-instrument is the final part of the setup and is marked by `;; @instrument` above the module.
2. Use comment to specify the `whamm!` script, syntax: `;; WHAMM --> <whamm_script>`
- The scripts are run on the `module` in the `.wast` file.
- If there are multiple `asserts` under a `whamm!` comment, they are all run against the instrumented variation of the `module` that results from that `whamm!` script.
Expand Down
4 changes: 0 additions & 4 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ pub struct InstrArgs {
/// Whether to emit Virgil code as the instrumentation code
#[arg(short, long, action, default_value = "false")]
pub virgil: bool,

/// Whether to run the verifier on the specified script
#[arg(long, short, action, default_value = "true")]
pub run_verifier: bool,
}

// pub fn print_completion<G: Generator>(gen: G, app: &mut App) {
Expand Down
6 changes: 3 additions & 3 deletions src/emitter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub mod tests;

use crate::common::error::WhammError;
use crate::emitter::rewriting::rules::{Arg, LocInfo, WhammProvider};
use crate::parser::types::{DataType, Expr, Fn, ProbeSpec, Statement, Value};
use crate::parser::types::{Block, DataType, Expr, Fn, ProbeSpec, Statement, Value};

use orca::ir::types::DataType as OrcaType;
use wasmparser::Operator;
Expand Down Expand Up @@ -46,7 +46,7 @@ pub trait ModuleEmitter {
/// Will configure the emitter to emit subsequent statements in the outer block of some branching logic
fn finish_branch(&mut self) -> bool;
fn emit_global_stmts(&mut self, stmts: &mut Vec<Statement>) -> Result<bool, Box<WhammError>>;
fn emit_body(&mut self, body: &mut Vec<Statement>) -> Result<bool, Box<WhammError>>;
fn emit_body(&mut self, body: &mut Block) -> Result<bool, Box<WhammError>>;
fn emit_stmt(&mut self, stmt: &mut Statement) -> Result<bool, Box<WhammError>>;

fn dump_to_file(&mut self, output_wasm_path: String) -> Result<bool, Box<WhammError>>;
Expand Down Expand Up @@ -95,7 +95,7 @@ pub trait VisitingEmitter {
/// Will configure the emitter to emit subsequent statements in the outer block of some branching logic
fn finish_branch(&mut self) -> bool;
fn emit_global_stmts(&mut self, stmts: &mut Vec<Statement>) -> Result<bool, Box<WhammError>>;
fn emit_body(&mut self, body: &mut Vec<Statement>) -> Result<bool, Box<WhammError>>;
fn emit_body(&mut self, body: &mut Block) -> Result<bool, Box<WhammError>>;
fn emit_stmt(&mut self, stmt: &mut Statement) -> Result<bool, Box<WhammError>>;

fn dump_to_file(&mut self, output_wasm_path: String) -> Result<bool, Box<WhammError>>;
Expand Down
75 changes: 39 additions & 36 deletions src/emitter/rewriting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub mod rules;
pub mod visiting_emitter;

use crate::common::error::{ErrorGen, WhammError};
use crate::parser::types::{BinOp, DataType, Expr, Statement, UnOp, Value};
use crate::parser::types::{BinOp, Block, DataType, Expr, Statement, UnOp, Value};
use crate::verifier::types::{Record, SymbolTable, VarAddr};

use crate::emitter::rewriting::module_emitter::MemoryTracker;
Expand All @@ -14,7 +14,7 @@ use orca::{InitExpr, ModuleBuilder};
use wasmparser::{BlockType, ValType};

pub trait Emitter {
fn emit_body(&mut self, body: &mut [Statement]) -> Result<bool, Box<WhammError>>;
fn emit_body(&mut self, body: &mut Block) -> Result<bool, Box<WhammError>>;
fn emit_stmt(&mut self, stmt: &mut Statement) -> Result<bool, Box<WhammError>>;
fn emit_expr(&mut self, expr: &mut Expr) -> Result<bool, Box<WhammError>>;
}
Expand All @@ -31,13 +31,13 @@ pub trait Emitter {
// ==================================================================

fn emit_body<'a, T: Opcode<'a> + ModuleBuilder>(
body: &mut [Statement],
body: &mut Block,
injector: &mut T,
table: &mut SymbolTable,
mem_tracker: &MemoryTracker,
err_msg: &str,
) -> Result<bool, Box<WhammError>> {
for stmt in body.iter_mut() {
for stmt in body.stmts.iter_mut() {
emit_stmt(stmt, injector, table, mem_tracker, err_msg)?;
}
Ok(true)
Expand All @@ -53,32 +53,18 @@ fn emit_stmt<'a, T: Opcode<'a> + ModuleBuilder>(
match stmt {
Statement::Decl { .. } => emit_decl_stmt(stmt, injector, table, err_msg),
Statement::Assign { .. } => emit_assign_stmt(stmt, injector, table, mem_tracker, err_msg),
Statement::Expr { expr, .. } => emit_expr(expr, injector, table, mem_tracker, err_msg),
Statement::Expr { expr, .. } | Statement::Return { expr, .. } => {
emit_expr(expr, injector, table, mem_tracker, err_msg)
}
Statement::If {
cond, conseq, alt, ..
} => {
if alt.stmts.is_empty() {
emit_if(
cond,
conseq.stmts.as_mut_slice(),
injector,
table,
mem_tracker,
err_msg,
)
emit_if(cond, conseq, injector, table, mem_tracker, err_msg)
} else {
emit_if_else(
cond,
conseq.stmts.as_mut_slice(),
alt.stmts.as_mut_slice(),
injector,
table,
mem_tracker,
err_msg,
)
emit_if_else(cond, conseq, alt, injector, table, mem_tracker, err_msg)
}
}
Statement::Return { .. } => unimplemented!(),
}
}

Expand Down Expand Up @@ -287,6 +273,15 @@ pub fn whamm_type_to_wasm(ty: &DataType) -> Global {
DataType::AssumeGood => unimplemented!(),
}
}
pub fn block_type_to_wasm(block: &Block) -> BlockType {
match &block.return_ty {
None => BlockType::Empty,
Some(return_ty) => {
let wasm_ty = whamm_type_to_wasm(return_ty).ty.content_type;
BlockType::Type(wasm_ty)
}
}
}

fn emit_set<'a, T: Opcode<'a>>(
var_id: &mut Expr,
Expand Down Expand Up @@ -345,7 +340,7 @@ fn emit_set<'a, T: Opcode<'a>>(

fn emit_if_preamble<'a, T: Opcode<'a> + ModuleBuilder>(
condition: &mut Expr,
conseq: &mut [Statement],
conseq: &mut Block,
injector: &mut T,
table: &mut SymbolTable,
mem_tracker: &MemoryTracker,
Expand All @@ -356,7 +351,7 @@ fn emit_if_preamble<'a, T: Opcode<'a> + ModuleBuilder>(
// emit the condition of the `if` expression
is_success &= emit_expr(condition, injector, table, mem_tracker, err_msg)?;
// emit the beginning of the if block
injector.if_stmt(BlockType::Empty);
injector.if_stmt(block_type_to_wasm(conseq));

// emit the consequent body
is_success &= emit_body(conseq, injector, table, mem_tracker, err_msg)?;
Expand All @@ -368,8 +363,8 @@ fn emit_if_preamble<'a, T: Opcode<'a> + ModuleBuilder>(

fn emit_if_else_preamble<'a, T: Opcode<'a> + ModuleBuilder>(
condition: &mut Expr,
conseq: &mut [Statement],
alternate: &mut [Statement],
conseq: &mut Block,
alternate: &mut Block,
injector: &mut T,
table: &mut SymbolTable,
mem_tracker: &MemoryTracker,
Expand All @@ -392,7 +387,7 @@ fn emit_if_else_preamble<'a, T: Opcode<'a> + ModuleBuilder>(

fn emit_if<'a, T: Opcode<'a> + ModuleBuilder>(
condition: &mut Expr,
conseq: &mut [Statement],
conseq: &mut Block,
injector: &mut T,
table: &mut SymbolTable,
mem_tracker: &MemoryTracker,
Expand All @@ -409,8 +404,8 @@ fn emit_if<'a, T: Opcode<'a> + ModuleBuilder>(

fn emit_if_else<'a, T: Opcode<'a> + ModuleBuilder>(
condition: &mut Expr,
conseq: &mut [Statement],
alternate: &mut [Statement],
conseq: &mut Block,
alternate: &mut Block,
injector: &mut T,
table: &mut SymbolTable,
mem_tracker: &MemoryTracker,
Expand Down Expand Up @@ -458,14 +453,22 @@ fn emit_expr<'a, T: Opcode<'a> + ModuleBuilder>(
// change conseq and alt types to stmt for easier API call
is_success &= emit_if_else(
cond,
&mut vec![Statement::Expr {
expr: (**conseq).clone(),
&mut Block {
stmts: vec![Statement::Expr {
expr: (**conseq).clone(),
loc: None,
}],
return_ty: None,
loc: None,
}],
&mut vec![Statement::Expr {
expr: (**alt).clone(),
},
&mut Block {
stmts: vec![Statement::Expr {
expr: (**alt).clone(),
loc: None,
}],
return_ty: None,
loc: None,
}],
},
injector,
table,
mem_tracker,
Expand Down
70 changes: 48 additions & 22 deletions src/emitter/rewriting/module_emitter.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::common::error::{ErrorGen, WhammError};
use crate::parser::types::{DataType, Definition, Expr, Fn, Statement, Value};
use crate::parser::types::{Block, DataType, Definition, Expr, Fn, Statement, Value};
use crate::verifier::types::{Record, SymbolTable, VarAddr};
use orca::{DataSegment, DataSegmentKind, InitExpr};
use std::collections::HashMap;

use orca::ir::types::{DataType as OrcaType, Value as OrcaValue};
use wasmparser::BlockType;
use wasmparser::{BlockType, GlobalType};

use crate::emitter::rewriting::{emit_body, emit_expr, emit_stmt, whamm_type_to_wasm, Emitter};
use orca::ir::function::FunctionBuilder;
Expand Down Expand Up @@ -292,6 +292,26 @@ impl<'a, 'b, 'c, 'd> ModuleEmitter<'a, 'b, 'c, 'd> {
}
}

pub(crate) fn emit_global_getter(
&mut self,
global_id: &u32,
name: String,
ty: &GlobalType,
) -> Result<bool, Box<WhammError>> {
let getter_params = vec![];
let getter_res = vec![OrcaType::from(ty.content_type)];

let mut getter = FunctionBuilder::new(&getter_params, &getter_res);
getter.global_get(*global_id);

let getter_id = getter.finish(self.app_wasm);

let fn_name = format!("get_{name}");
self.app_wasm.add_export_func(fn_name.leak(), getter_id);

Ok(true)
}

pub(crate) fn emit_global(
&mut self,
name: String,
Expand All @@ -313,33 +333,39 @@ impl<'a, 'b, 'c, 'd> ModuleEmitter<'a, 'b, 'c, 'd> {
};

let rec = self.table.get_record_mut(&rec_id);
match rec {
let (global_id, ty) = match rec {
Some(Record::Var { ref mut addr, .. }) => {
// emit global variable and set addr in symbol table
// this is used for user-defined global vars in the script...
let default_global = whamm_type_to_wasm(&ty);
let global_id = self.app_wasm.add_global(default_global);
let global_id = self.app_wasm.add_global(default_global.clone());
*addr = Some(VarAddr::Global { addr: global_id });
Ok(true)
(global_id, default_global.ty)
}
Some(&mut ref ty) => Err(Box::new(ErrorGen::get_unexpected_error(
true,
Some(format!(
"{UNEXPECTED_ERR_MSG} \
Some(&mut ref ty) => {
return Err(Box::new(ErrorGen::get_unexpected_error(
true,
Some(format!(
"{UNEXPECTED_ERR_MSG} \
Incorrect global variable record, expected Record::Var, found: {:?}",
ty
)),
None,
))),
None => Err(Box::new(ErrorGen::get_unexpected_error(
true,
Some(format!(
"{UNEXPECTED_ERR_MSG} \
ty
)),
None,
)))
}
None => {
return Err(Box::new(ErrorGen::get_unexpected_error(
true,
Some(format!(
"{UNEXPECTED_ERR_MSG} \
Global variable symbol does not exist!"
)),
None,
))),
}
)),
None,
)))
}
};

self.emit_global_getter(&global_id, name, &ty)
}

pub fn emit_global_stmts(&mut self, stmts: &mut [Statement]) -> Result<bool, Box<WhammError>> {
Expand Down Expand Up @@ -389,7 +415,7 @@ impl<'a, 'b, 'c, 'd> ModuleEmitter<'a, 'b, 'c, 'd> {
}
}
impl Emitter for ModuleEmitter<'_, '_, '_, '_> {
fn emit_body(&mut self, body: &mut [Statement]) -> Result<bool, Box<WhammError>> {
fn emit_body(&mut self, body: &mut Block) -> Result<bool, Box<WhammError>> {
if let Some(emitting_func) = &mut self.emitting_func {
emit_body(
body,
Expand Down
Loading