WIP: command line utility and start of Wasm-parsing frontend.
This commit is contained in:
parent
8a2e3e5eed
commit
1cca77ec37
|
@ -2,10 +2,14 @@
|
|||
name = "waffle"
|
||||
version = "0.0.1"
|
||||
description = "Wasm Analysis Framework For Lightweight Experiments"
|
||||
author = ["Chris Fallin <chris@cfallin.org>"]
|
||||
authors = ["Chris Fallin <chris@cfallin.org>"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmparser = "0.81"
|
||||
wasm-encoder = "0.3"
|
||||
anyhow = "1.0"
|
||||
structopt = "0.3"
|
||||
log = "0.4"
|
||||
env_logger = "0.9"
|
47
src/bin/waffle-util.rs
Normal file
47
src/bin/waffle-util.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
//! WAFFLE command-line tool.
|
||||
|
||||
use anyhow::Result;
|
||||
use log::debug;
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
use waffle::frontend;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "waffle-util", about = "WAFFLE utility.")]
|
||||
struct Options {
|
||||
#[structopt(short, long)]
|
||||
debug: bool,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
enum Command {
|
||||
#[structopt(name = "print-ir", about = "Parse Wasm and print resulting IR")]
|
||||
PrintIR {
|
||||
#[structopt(help = "Wasm file to parse")]
|
||||
wasm: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let opts = Options::from_args();
|
||||
|
||||
let mut logger = env_logger::Builder::from_default_env();
|
||||
if opts.debug {
|
||||
logger.filter_level(log::LevelFilter::Debug);
|
||||
}
|
||||
let _ = logger.try_init();
|
||||
|
||||
match opts.command {
|
||||
Command::PrintIR { wasm } => {
|
||||
let bytes = std::fs::read(wasm)?;
|
||||
debug!("Loaded {} bytes of Wasm data", bytes.len());
|
||||
let module = frontend::wasm_to_ir(&bytes[..])?;
|
||||
println!("{:?}", module);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
39
src/frontend.rs
Normal file
39
src/frontend.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
//! Frontend: convert Wasm to IR.
|
||||
|
||||
use crate::ir::*;
|
||||
use anyhow::{bail, Result};
|
||||
use log::debug;
|
||||
use wasmparser::{Chunk, Parser, Payload, TypeDef};
|
||||
|
||||
pub fn wasm_to_ir(bytes: &[u8]) -> Result<Module> {
|
||||
let mut module = Module::default();
|
||||
let mut parser = Parser::new(0);
|
||||
for chunk in parser.parse(bytes, /* eof = */ true) {
|
||||
match chunk {
|
||||
Chunk::NeedMoreData(_) => bail!("Unexpected EOF in Wasm"),
|
||||
Chunk::Parsed { payload, .. } => handle_payload(&mut module, payload)?,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
fn handle_payload<'a>(module: &mut Module, payload: Payload<'a>) -> Result<()> {
|
||||
debug!("Wasm parser item: {:?}", payload);
|
||||
match payload {
|
||||
Payload::TypeSection(mut reader) => {
|
||||
for _ in 0..reader.get_count() {
|
||||
let ty = reader.read()?;
|
||||
match ty {
|
||||
TypeDef::Func(fty) => {
|
||||
module.signatures.push(fty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
39
src/ir.rs
39
src/ir.rs
|
@ -1,13 +1,14 @@
|
|||
//! Intermediate representation for Wasm.
|
||||
|
||||
use wasmparser::{FuncType, Type};
|
||||
use wasmparser::{FuncType, Operator, Type};
|
||||
|
||||
pub type SignatureId = usize;
|
||||
pub type FuncId = usize;
|
||||
pub type BlockId = usize;
|
||||
pub type InstId = usize;
|
||||
pub type ValueId = usize;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Module {
|
||||
pub funcs: Vec<FuncDecl>,
|
||||
pub signatures: Vec<FuncType>,
|
||||
|
@ -19,8 +20,40 @@ pub enum FuncDecl {
|
|||
Body(SignatureId, FunctionBody),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct FunctionBody {
|
||||
pub locals: Vec<Type>,
|
||||
pub blocks: Vec<Block>,
|
||||
pub values: Vec<ValueDef>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ValueDef {
|
||||
pub kind: ValueKind,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ValueKind {
|
||||
BlockParam(Block),
|
||||
Inst(Block, Inst),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Block {
|
||||
pub params: Vec<Type>,
|
||||
pub insts: Vec<Inst>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Inst {
|
||||
pub operator: Operator<'static>,
|
||||
pub outputs: Vec<ValueId>,
|
||||
pub inputs: Vec<Operand>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Operand {
|
||||
Value(ValueId),
|
||||
Sub(Box<Inst>),
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
// Re-export wasmparser and wasmencoder for easier use of the right
|
||||
// version by our embedders.
|
||||
pub use wasmparser;
|
||||
pub use wasm_encoder;
|
||||
pub use wasmparser;
|
||||
|
||||
pub mod frontend;
|
||||
pub mod ir;
|
||||
|
|
Loading…
Reference in a new issue