From 88edc83aab212bd4a7d9123394382ea0a93e05f2 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 1 Jun 2024 02:00:14 +0800 Subject: [PATCH] Impl sleigh aware --- Cargo.lock | 129 ++++++++++++++++++++++++++++++++++++++- Cargo.toml | 6 +- il-tests/Cargo.toml | 10 ++- il-tests/build.rs | 1 - il-tests/src/lib.rs | 6 +- il-tests/src/main.rs | 141 ++++++++++++++++++++++++++----------------- src/wrapper.rs | 23 ++++--- 7 files changed, 239 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8adcc4..53a1637 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,28 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -338,6 +360,43 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -409,13 +468,17 @@ name = "il-tests" version = "0.1.0" dependencies = [ "anyhow", + "async-stream", + "bitvec", "clap", "dashmap", + "futures-util", "hex", "itertools 0.13.0", + "rand", "rayon", "rizin-rs", - "sleigh-rs", + "sleigh-rs 0.1.5", "sleigh2rust", ] @@ -594,6 +657,18 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "plotters" version = "0.3.5" @@ -754,6 +829,7 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" name = "rizin-rs" version = "0.1.2" dependencies = [ + "anyhow", "bindgen", "criterion", "glob", @@ -838,6 +914,24 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "sleigh-rs" +version = "0.1.5" +dependencies = [ + "nom", + "thiserror", + "tracing", +] + [[package]] name = "sleigh-rs" version = "0.1.5" @@ -859,7 +953,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "sleigh-rs", + "sleigh-rs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -921,6 +1015,37 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "unicode-ident" version = "1.0.12" diff --git a/Cargo.toml b/Cargo.toml index d0f1393..678462f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,8 @@ doctest = false [workspace] members = [ - "il-tests" + "il-tests", + "sleigh-rs", ] [dev-dependencies] @@ -32,3 +33,6 @@ rand = "0.8.5" [[bench]] name = "my_benchmark" harness = false + +[dependencies] +anyhow = "1.0.86" diff --git a/il-tests/Cargo.toml b/il-tests/Cargo.toml index d4082c8..8012cb1 100644 --- a/il-tests/Cargo.toml +++ b/il-tests/Cargo.toml @@ -11,10 +11,14 @@ dashmap = "5.5.3" hex = "0.4.3" itertools = "0.13.0" rayon = "1.10.0" -sleigh-rs = "0.1.5" +sleigh-rs = { path = "../sleigh-rs" } +rizin-rs = { path = ".." } +bitvec = "1.0.1" +anyhow = "1.0.86" +rand = "0.8.5" +async-stream = "0.3.5" +futures-util = "0.3.30" -[dependencies.rizin-rs] -path = ".." [build-dependencies] anyhow = "1.0.86" diff --git a/il-tests/build.rs b/il-tests/build.rs index cb155b9..0434b49 100644 --- a/il-tests/build.rs +++ b/il-tests/build.rs @@ -19,6 +19,5 @@ fn main() { let x = generate_disassembler(&p).unwrap(); let f = File::create(out_dir.join("tricore.rs")).unwrap(); let mut w = BufWriter::new(f); - rust w.write(x.to_string().as_bytes()).unwrap(); } diff --git a/il-tests/src/lib.rs b/il-tests/src/lib.rs index 02ddd16..0ddd50d 100644 --- a/il-tests/src/lib.rs +++ b/il-tests/src/lib.rs @@ -1,3 +1,3 @@ -pub mod gen { - include!(concat!(env!("OUT_DIR"), "/tricore.rs")); -} +// pub mod gen { +// include!(concat!(env!("OUT_DIR"), "/tricore.rs")); +// } diff --git a/il-tests/src/main.rs b/il-tests/src/main.rs index 5a9efb2..86867a9 100644 --- a/il-tests/src/main.rs +++ b/il-tests/src/main.rs @@ -1,13 +1,21 @@ +#![feature(coroutine_trait)] +#![feature(coroutines)] + use std::error::Error; +use std::fmt; +use std::path::PathBuf; use std::rc::Rc; +use anyhow::{anyhow, Result}; +use bitvec::prelude::*; use clap::Parser; -use dashmap::DashMap; use hex::ToHex; use itertools::Itertools; -use il_tests::gen; +use rand::Rng; use rizin_rs::wrapper::{AnalysisOp, Core}; +use sleigh_rs::file_to_sleigh; +use sleigh_rs::pattern::BitConstraint; struct Instruction { bytes: Vec, @@ -16,12 +24,12 @@ struct Instruction { } impl Instruction { - fn from_bytes(core: &Core, bytes: &[u8], addr: usize) -> Result { + fn from_bytes(core: &Core, bytes: &[u8], addr: usize) -> Result { let op = core.analysis_op(bytes, addr)?; let mnemonic = op.mnemonic()?; let bytes = &bytes[0..op.0.size as usize]; match mnemonic.split_whitespace().next() { - None => Err(()), + None => Err(anyhow!("Invalid")), Some(m) => Ok(Self { bytes: Vec::from(bytes), mnemonic: Rc::new(m.to_string()), @@ -32,16 +40,24 @@ impl Instruction { } impl Instruction { - fn try_to_string(&self) -> rizin_rs::wrapper::Result { + fn try_to_string(&self, il: bool) -> rizin_rs::wrapper::Result { + let mut res = String::new(); let op_str = self.op.mnemonic()?; - let il_str = self.op.il_str(false)?; - Ok(format!( - "d \"{}\" {} {:#08x} {}", - op_str, - self.bytes.encode_hex::(), - self.op.0.addr, - il_str - )) + fmt::write( + &mut res, + format_args!( + "d \"{}\" {} {:#08x}", + op_str, + self.bytes.encode_hex::(), + self.op.0.addr + ), + )?; + + if il { + let il_str = self.op.il_str(false)?; + fmt::write(&mut res, format_args!(" {}", il_str))?; + } + Ok(res) } } @@ -49,24 +65,46 @@ impl Instruction { #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { - #[arg(short, long, default_value = "pic")] + #[arg(short, long, default_value = "tricore")] arch: String, - #[arg(short, long, default_value = "pic18")] + #[arg(short, long, default_value = "tricore")] cpu: String, - - #[arg(short, long)] - max: Option, } -const INST_LIMIT: usize = 0x8_usize; -const ADDRS: [usize; 2] = [0, 0xff00]; +struct InstructionConstraint(Vec); + +impl InstructionConstraint { + fn sample_data(&self, rng: &mut R) -> Vec { + let iter = self.0.iter().map(|x| match x { + BitConstraint::Unrestrained => rng.gen_bool(0.5), + BitConstraint::Defined(x) => *x, + BitConstraint::Restrained => false, + }); + let data = BitVec::::from_iter(iter).as_raw_slice().into(); + data + } + + fn sample_ops<'a, R: Rng + ?Sized>( + &'a self, + core: &'a Core, + addr: usize, + rng: &'a mut R, + count: usize, + ) -> Vec { + (0..count) + .filter_map(|_| { + let data = self.sample_data(rng); + Instruction::from_bytes(core, &data, addr).ok() + }) + .filter(|x| !x.mnemonic.to_lowercase().contains("invalid")) + .collect_vec() + } +} fn main() -> Result<(), Box> { let args = Args::parse(); - let max = args.max.unwrap_or(u16::MAX as _); - let map = DashMap::, usize>::new(); let core = { let core = Core::new(); core.set("analysis.arch", &args.arch).unwrap(); @@ -75,40 +113,29 @@ fn main() -> Result<(), Box> { core }; - - - // let _ = (0..max) - // .flat_map(|x| { - // let b = x.to_le_bytes(); - // ADDRS - // .iter() - // .filter_map(|addr| { - // let inst = { Instruction::from_bytes(&core, &b, addr.clone()) }; - // if inst.is_err() { - // return None; - // } - // let inst = inst.unwrap(); - // let entry = map.get_mut(&inst.mnemonic); - // match entry { - // Some(x) if *x > INST_LIMIT => return None, - // _ => {} - // } - // - // match entry { - // None => { - // map.insert(inst.mnemonic.clone(), 1); - // } - // Some(mut k) => { - // *k += 1; - // } - // }; - // Some(inst) - // }) - // .collect::>() - // }) - // .sorted_by_key(|x| x.mnemonic.clone()) - // .for_each(|x| { - // let _ = x.try_to_string().map(|str| println!("{}", str)); - // }); + let p = PathBuf::from(format!( + "ghidra/Ghidra/Processors/{}/data/languages/{}.slaspec", + &args.arch, &args.cpu + )); + let sleigh = file_to_sleigh(&p)?; + let insttbl = sleigh.table(sleigh.instruction_table()); + let mut rng = rand::thread_rng(); + insttbl + .constructors() + .iter() + .flat_map(|ctor| { + // let m = ctor.display.mneumonic.as_ref().unwrap(); + ctor.pattern + .pattern_bits_variants(&sleigh) + .flat_map(|(_, _, b)| { + let x = InstructionConstraint(b); + x.sample_ops(&core, 0x0, &mut rng, 3) + }) + .collect_vec() + }) + .sorted_by_key(|x| x.mnemonic.clone()) + .for_each(|x| { + let _ = x.try_to_string(true).map(|str| println!("{}", str)); + }); Ok(()) } diff --git a/src/wrapper.rs b/src/wrapper.rs index a65dd1b..6d345bd 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use std::ffi::{CStr, CString}; use std::fmt::Display; use std::marker::PhantomData; @@ -9,7 +10,7 @@ use std::{fmt, result, slice}; use crate::*; -pub type Result = result::Result; +pub type Result = anyhow::Result; pub struct Core(pub NonNull); unsafe impl Sync for Core {} @@ -69,16 +70,16 @@ impl Drop for StrBuf { impl AnalysisOp { pub fn mnemonic(&self) -> Result<&str> { if self.0.mnemonic.is_null() { - Err(()) + Err(anyhow!("mnemonic is_null")) } else { let cstr = unsafe { CStr::from_ptr(self.0.mnemonic) }; - cstr.to_str().map_err(|_| ()) + cstr.to_str().map_err(|_| anyhow!("invalid cstr")) } } pub fn il_str(&self, pretty: bool) -> Result { if self.0.il_op.is_null() { - Err(()) + Err(anyhow!("il_op is null")) } else { let mut sb = StrBuf::new(); unsafe { @@ -109,7 +110,7 @@ impl Core { ) }; if res <= 0 { - Err(()) + Err(anyhow!("failed analysis op")) } else { Ok(op) } @@ -119,11 +120,13 @@ impl Core { let node = unsafe { rz_config_set( self.0.as_ref().config, - CString::new(k).map_err(|_| ())?.as_ptr(), - CString::new(v).map_err(|_| ())?.as_ptr(), + CString::new(k)?.as_ptr(), + CString::new(v)?.as_ptr(), ) }; - NonNull::new(node).map(|_| self).ok_or(()) + NonNull::new(node) + .map(|_| self) + .ok_or(anyhow!("{} is null", k)) } } @@ -140,7 +143,7 @@ impl Core { let bf = rz_bin_open(self.0.as_ref().bin, cpath.as_ptr(), &mut rz_bin_opt); Ok(BinFile { core: self, - bf: NonNull::new(bf).ok_or(())?, + bf: NonNull::new(bf).ok_or(anyhow!("failed open {}", path.to_str().unwrap()))?, }) } } @@ -174,7 +177,7 @@ impl DwarfAbbrev { let abbrev = unsafe { rz_bin_dwarf_abbrev_new(addr_of_mut!(R)) }; NonNull::::new(abbrev) .map(DwarfAbbrev) - .ok_or(()) + .ok_or(anyhow!("failed new")) } }