Skip to content
Draft
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
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/c_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ links = "wasmi_c_api"
[dependencies]
wasmi = { workspace = true }
wasmi_c_api_macros = { workspace = true }
wasmi_tracer = { workspace = true }

[lib]
name = "wasmi_c_api"
Expand Down
4 changes: 3 additions & 1 deletion crates/c_api/src/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
use alloc::{boxed::Box, string::String, vec, vec::Vec};
use core::{any::Any, ffi::c_void, hint, iter, ptr, str};
use wasmi::{Error, Extern, Func, FuncRef, Val};
use wasmi_tracer::WasmTracer;

#[cfg(feature = "std")]
use core::panic::AssertUnwindSafe;
Expand Down Expand Up @@ -210,7 +211,8 @@ pub unsafe extern "C" fn wasm_func_call(
// can. As a result we catch panics here and transform them to traps to
// allow the caller to have any insulation possible against Rust panics.
std::panic::catch_unwind(AssertUnwindSafe(|| {
f.call(func.inner.store.context_mut(), wt_params, wt_results)
let mut tracer = WasmTracer::no_tracing();
f.call(func.inner.store.context_mut(), wt_params, wt_results, &mut tracer)
}))
}
#[cfg(not(feature = "std"))]
Expand Down
4 changes: 3 additions & 1 deletion crates/c_api/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
};
use alloc::boxed::Box;
use wasmi::Instance;
use wasmi_tracer::WasmTracer;

/// A Wasm instance.
///
Expand Down Expand Up @@ -56,7 +57,8 @@ pub unsafe extern "C" fn wasm_instance_new(
.iter()
.filter_map(|import| import.as_ref().map(|i| i.which))
.collect::<Box<[_]>>();
match Instance::new(store.inner.context_mut(), &wasm_module.inner, &imports) {
let mut tracer = WasmTracer::no_tracing();
match Instance::new(store.inner.context_mut(), &wasm_module.inner, &imports, &mut tracer) {
Ok(instance) => Some(Box::new(wasm_instance_t::new(
store.inner.clone(),
instance,
Expand Down
1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ exclude.workspace = true
[dependencies]
wasmi = { workspace = true, features = ["wat"] }
wasmi_wasi = { workspace = true }
wasmi_tracer = { workspace = true }
anyhow = "1"
clap = { version = "4", features = ["derive"] }

Expand Down
11 changes: 11 additions & 0 deletions crates/cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ pub struct Args {
/// Arguments given to the Wasm module or the invoked function.
#[clap(value_name = "ARGS")]
func_args: Vec<String>,

#[clap(
long = "trace",
default_value_t = false,
)]
tracing: bool,
}

/// The chosen Wasmi compilation mode.
Expand Down Expand Up @@ -151,6 +157,11 @@ impl Args {
self.verbose
}

/// Returns `true` if tracing is enabled.
pub fn tracing(&self) -> bool {
self.tracing
}

/// Pre-opens all directories given in `--dir` and returns them for use by the [`WasiCtx`].
///
/// # Errors
Expand Down
6 changes: 5 additions & 1 deletion crates/cli/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::{anyhow, Error};
use std::{fs, path::Path};
use wasmi::{CompilationMode, Config, ExternType, Func, FuncType, Instance, Module, Store};
use wasmi_wasi::WasiCtx;
use wasmi_tracer::WasmTracer;

/// The [`Context`] for the Wasmi CLI application.
///
Expand All @@ -13,6 +14,8 @@ pub struct Context {
store: Store<WasiCtx>,
/// The Wasm module instance to operate on.
instance: Instance,
// Is the tracing enabled
// tracing: bool,
}

impl Context {
Expand All @@ -27,6 +30,7 @@ impl Context {
wasi_ctx: WasiCtx,
fuel: Option<u64>,
compilation_mode: CompilationMode,
tracer: &mut WasmTracer,
) -> Result<Self, Error> {
let mut config = Config::default();
if fuel.is_some() {
Expand All @@ -52,7 +56,7 @@ impl Context {
.map_err(|error| anyhow!("failed to add WASI definitions to the linker: {error}"))?;
let instance = linker
.instantiate(&mut store, &module)
.and_then(|pre| pre.start(&mut store))
.and_then(|pre| pre.start(&mut store, tracer))
.map_err(|error| anyhow!("failed to instantiate and start the Wasm module: {error}"))?;
Ok(Self {
module,
Expand Down
7 changes: 5 additions & 2 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use clap::Parser;
use context::Context;
use std::{path::Path, process};
use wasmi::{Func, FuncType, Val};
use wasmi_tracer::WasmTracer;

mod args;
mod context;
Expand All @@ -20,7 +21,9 @@ fn main() -> Result<()> {
let args = Args::parse();
let wasm_file = args.wasm_file();
let wasi_ctx = args.wasi_context()?;
let mut ctx = Context::new(wasm_file, wasi_ctx, args.fuel(), args.compilation_mode())?;
let wasm_file_full_path = std::fs::canonicalize(&wasm_file)?;
let mut tracer = WasmTracer::new(args.tracing(), &wasm_file_full_path);
let mut ctx = Context::new(wasm_file, wasi_ctx, args.fuel(), args.compilation_mode(), &mut tracer)?;
let (func_name, func) = get_invoked_func(&args, &ctx)?;
let ty = func.ty(ctx.store());
let func_args = utils::decode_func_args(&ty, args.func_args())?;
Expand All @@ -39,7 +42,7 @@ fn main() -> Result<()> {
)
}

match func.call(ctx.store_mut(), &func_args, &mut func_results) {
match func.call(ctx.store_mut(), &func_args, &mut func_results, &mut tracer) {
Ok(()) => {
print_remaining_fuel(&args, &ctx);
print_pretty_results(&func_results);
Expand Down
11 changes: 10 additions & 1 deletion crates/tracer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ impl DebugInfo {

#[derive(Debug, Clone)]
pub struct WasmTracer {
pub tracing: bool,
debug_info: DebugInfo,
// TODO: tracer: runtime_tracing.Tracer,
// etc
Expand All @@ -33,12 +34,20 @@ pub struct WasmTracer {
// just to make it build so we can branch-out

impl WasmTracer {
pub fn new(wasm_exe_path: &Path) -> Self {
pub fn new(tracing: bool, wasm_exe_path: &Path) -> Self {
WasmTracer {
tracing,
debug_info: DebugInfo::new(wasm_exe_path),
}
}

pub fn no_tracing() -> Self {
WasmTracer {
tracing: false,
debug_info: DebugInfo::new(&Path::new("")),
}
}

pub fn load_local_variables(&mut self, address: usize) { // -> ???
println!("load_local_variables {address}");
// e.g. here we might call something like
Expand Down
1 change: 1 addition & 0 deletions crates/wasmi/src/engine/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct Config {
compilation_mode: CompilationMode,
/// Enforced limits for Wasm module parsing and compilation.
limits: EnforcedLimits,
// tracing: bool,
}

/// Type storing all kinds of fuel costs of instructions.
Expand Down
32 changes: 18 additions & 14 deletions crates/wasmi/src/engine/executor/instrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ pub fn execute_instrs<'engine, T>(
store: &mut Store<T>,
stack: &'engine mut Stack,
code_map: &'engine CodeMap,
tracer: &'engine mut WasmTracer,
) -> Result<(), Error> {
let instance = stack.calls.instance_expect();
let cache = CachedInstance::new(&mut store.inner, instance);
Executor::new(stack, code_map, cache).execute(store)
Executor::new(stack, code_map, cache).execute(store, tracer)
}

/// An execution context for executing a Wasmi function frame.
Expand All @@ -94,7 +95,8 @@ struct Executor<'engine> {
code_map: &'engine CodeMap,

// debug:
// TODO tracer: &'engine mut WasmTracer,
// tracer: &'engine mut WasmTracer,
// tracing: bool,
}

impl<'engine> Executor<'engine> {
Expand All @@ -104,6 +106,7 @@ impl<'engine> Executor<'engine> {
stack: &'engine mut Stack,
code_map: &'engine CodeMap,
cache: CachedInstance,
// tracer: &'engine mut WasmTracer,
) -> Self {
let frame = stack
.calls
Expand All @@ -121,25 +124,26 @@ impl<'engine> Executor<'engine> {
cache,
stack,
code_map,
// TODO tracer: &mut tracer, // probably were not gonna make it
// tracer,
// tracing,
}
}

/// Executes the function frame until it returns or traps.
#[inline(always)]
fn execute<T>(mut self, store: &mut Store<T>) -> Result<(), Error> {
fn execute<T>(mut self, store: &mut Store<T>, tracer: &mut WasmTracer) -> Result<(), Error> {
use Instruction as Instr;
loop {
// TODO: change that, just startting from somewehre
// Args: path : Path, instruction address(?) , step?
// TODO: good way to take address
//let address = usize::from(self.ip.get());
let address = 0x000000010; // should be in the main subprogram >= low_pc
//std::println!("address of {:?}: {:?}", *self.ip.get(), address);
// TODO: make this be a field with correct lifetime
let mut tracer = WasmTracer::new(std::path::Path::new("/home/pesho/code/codetracer-wasmi-recorder/wasm_test.wasm")); // "<path to test.wasm>: for now hardcoded TODO pass");
tracer.load_local_variables(address);

if tracer.tracing {
std::println!("{:?}", tracer);
// TODO: change that, just startting from somewehre
// Args: path : Path, instruction address(?) , step?
// TODO: good way to take address
//let address = usize::from(self.ip.get());
let address = 0x000000010; // should be in the main subprogram >= low_pc
// TODO: make this be a field with correct lifetime
tracer.load_local_variables(address);
}
// load debuginfo from gimli <- for this ip;
// -> find out current scope and vars in it:
// some kind of mapping between them and locations
Expand Down
22 changes: 16 additions & 6 deletions crates/wasmi/src/engine/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use crate::engine::StackLimits;

use super::code_map::CodeMap;

use wasmi_tracer::WasmTracer;

mod cache;
mod instr_ptr;
mod instrs;
Expand All @@ -41,13 +43,14 @@ impl EngineInner {
func: &Func,
params: impl CallParams,
results: Results,
tracer: &mut WasmTracer,
) -> Result<<Results as CallResults>::Results, Error>
where
Results: CallResults,
{
let mut stack = self.stacks.lock().reuse_or_new();
let results = EngineExecutor::new(&self.code_map, &mut stack)
.execute_root_func(ctx.store, func, params, results)
.execute_root_func(ctx.store, func, params, results, tracer)
.map_err(|error| match error.into_resumable() {
Ok(error) => error.into_error(),
Err(error) => error,
Expand All @@ -69,14 +72,15 @@ impl EngineInner {
func: &Func,
params: impl CallParams,
results: Results,
tracer: &mut WasmTracer,
) -> Result<ResumableCallBase<<Results as CallResults>::Results>, Error>
where
Results: CallResults,
{
let store = ctx.store;
let mut stack = self.stacks.lock().reuse_or_new();
let results = EngineExecutor::new(&self.code_map, &mut stack)
.execute_root_func(store, func, params, results);
.execute_root_func(store, func, params, results, tracer);
match results {
Ok(results) => {
self.stacks.lock().recycle(stack);
Expand Down Expand Up @@ -117,6 +121,7 @@ impl EngineInner {
mut invocation: ResumableInvocation,
params: impl CallParams,
results: Results,
tracer: &mut WasmTracer,
) -> Result<ResumableCallBase<<Results as CallResults>::Results>, Error>
where
Results: CallResults,
Expand All @@ -129,6 +134,7 @@ impl EngineInner {
params,
caller_results,
results,
tracer,
);
match results {
Ok(results) => {
Expand Down Expand Up @@ -158,6 +164,8 @@ pub struct EngineExecutor<'engine> {
code_map: &'engine CodeMap,
/// The value and call stacks.
stack: &'engine mut Stack,
// wasm tracer
// tracer: &'engine mut WasmTracer,
}

/// Convenience function that does nothing to its `&mut` parameter.
Expand Down Expand Up @@ -185,6 +193,7 @@ impl<'engine> EngineExecutor<'engine> {
func: &Func,
params: impl CallParams,
results: Results,
tracer: &mut WasmTracer
) -> Result<<Results as CallResults>::Results, Error>
where
Results: CallResults,
Expand Down Expand Up @@ -217,7 +226,7 @@ impl<'engine> EngineExecutor<'engine> {
Some(instance),
)?;
store.invoke_call_hook(CallHook::CallingWasm)?;
self.execute_func(store)?;
self.execute_func(store, tracer)?;
store.invoke_call_hook(CallHook::ReturningFromWasm)?;
}
FuncEntity::Host(host_func) => {
Expand Down Expand Up @@ -259,6 +268,7 @@ impl<'engine> EngineExecutor<'engine> {
params: impl CallParams,
caller_results: RegSpan,
results: Results,
tracer: &mut WasmTracer
) -> Result<<Results as CallResults>::Results, Error>
where
Results: CallResults,
Expand All @@ -274,7 +284,7 @@ impl<'engine> EngineExecutor<'engine> {
for (result, param) in caller_results.iter_sized(len_params).zip(call_params) {
unsafe { caller_sp.set(result, param) };
}
self.execute_func(store)?;
self.execute_func(store, tracer)?;
let results = self.write_results_back(results);
Ok(results)
}
Expand All @@ -285,8 +295,8 @@ impl<'engine> EngineExecutor<'engine> {
///
/// When encountering a Wasm or host trap during execution.
#[inline(always)]
fn execute_func<T>(&mut self, store: &mut Store<T>) -> Result<(), Error> {
execute_instrs(store, self.stack, self.code_map)
fn execute_func<T>(&mut self, store: &mut Store<T>, tracer: &mut WasmTracer) -> Result<(), Error> {
execute_instrs(store, self.stack, self.code_map, tracer)
}

/// Convenience forwarder to [`dispatch_host_func`].
Expand Down
Loading