diff --git a/fugue-high/src/eval/dummy.rs b/fugue-high/src/eval/dummy.rs
new file mode 100644
index 0000000..b1f7367
--- /dev/null
+++ b/fugue-high/src/eval/dummy.rs
@@ -0,0 +1,123 @@
+use fugue_bv::BitVec;
+use fugue_bytes::Endian;
+use fugue_ir::{Address, VarnodeData};
+
+use crate::lifter::Lifter;
+
+use super::{EvaluatorContext, EvaluatorError, FixedState};
+
+pub struct DummyContext {
+ base: Address,
+ endian: Endian,
+ memory: FixedState,
+ registers: FixedState,
+ temporaries: FixedState,
+}
+
+impl DummyContext {
+ pub fn new(lifter: &Lifter, base: impl Into
, size: usize) -> Self {
+ let t = lifter.translator();
+
+ Self {
+ base: base.into(),
+ endian: if t.is_big_endian() {
+ Endian::Big
+ } else {
+ Endian::Little
+ },
+ memory: FixedState::new(size),
+ registers: FixedState::new(t.register_space_size()),
+ temporaries: FixedState::new(t.unique_space_size()),
+ }
+ }
+
+ fn translate(&self, addr: u64) -> Result {
+ let addr = addr
+ .checked_sub(self.base.into())
+ .ok_or(EvaluatorError::state_with(
+ "address translation out-of-bounds",
+ ))?;
+
+ Ok(addr as usize)
+ }
+}
+
+impl EvaluatorContext for DummyContext {
+ fn read_vnd(&mut self, var: &VarnodeData) -> Result {
+ let spc = var.space();
+ if spc.is_constant() {
+ Ok(BitVec::from_u64(var.offset(), var.size() * 8))
+ } else if spc.is_register() {
+ self.registers
+ .read_val_with(var.offset() as usize, var.size(), self.endian)
+ .map_err(EvaluatorError::state)
+ } else if spc.is_unique() {
+ self.temporaries
+ .read_val_with(var.offset() as usize, var.size(), self.endian)
+ .map_err(EvaluatorError::state)
+ } else {
+ let addr = self.translate(var.offset())?;
+ self.memory
+ .read_val_with(addr, var.size(), self.endian)
+ .map_err(EvaluatorError::state)
+ }
+ }
+
+ fn write_vnd(&mut self, var: &VarnodeData, val: &BitVec) -> Result<(), EvaluatorError> {
+ let spc = var.space();
+ if spc.is_register() {
+ self.registers
+ .write_val_with(var.offset() as usize, val, self.endian)
+ .map_err(EvaluatorError::state)
+ } else if spc.is_unique() {
+ self.temporaries
+ .write_val_with(var.offset() as usize, val, self.endian)
+ .map_err(EvaluatorError::state)
+ } else if spc.is_default() {
+ let addr = self.translate(var.offset())?;
+ self.memory
+ .write_val_with(addr, val, self.endian)
+ .map_err(EvaluatorError::state)
+ } else {
+ panic!("cannot write to constant Varnode")
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use crate::eval::Evaluator;
+ use crate::prelude::*;
+
+ use super::*;
+
+ #[test]
+ fn test_single_step() -> anyhow::Result<()> {
+ let lbuilder = LanguageBuilder::new("data")?;
+ let language = lbuilder.build("ARM:LE:32:v7", "default")?;
+
+ let memory = &[
+ 0x03, 0x00, 0x51, 0xE3, 0x0A, 0x00, 0x00, 0x9A, 0x00, 0x30, 0xA0, 0xE3, 0x01, 0x10,
+ 0x80, 0xE0, 0x03, 0x00, 0x80, 0xE2, 0x01, 0x20, 0xD0, 0xE4, 0x02, 0x30, 0x83, 0xE0,
+ 0x01, 0x00, 0x50, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0xFA, 0xFF, 0xFF, 0x1A, 0x00, 0x00,
+ 0x63, 0xE2, 0xFF, 0x00, 0x00, 0xE2, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0xA0, 0xE3,
+ 0x1E, 0xFF, 0x2F, 0xE1,
+ ];
+
+ let mut lifter = language.lifter();
+ let irb = lifter.irb(1024);
+
+ let pcode = lifter.lift(&irb, 0x15e38u32, memory)?;
+
+ let mut context = DummyContext::new(&lifter, 0x15e38u32, 0x1000);
+ let mut evaluator = Evaluator::new(&lifter, &mut context);
+
+ evaluator.context.memory.write_bytes(0usize, memory)?;
+
+ for op in pcode.operations() {
+ evaluator.step(0x15e38u32, &op)?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/fugue-high/src/eval/mod.rs b/fugue-high/src/eval/mod.rs
index 7a69bdf..76c9023 100644
--- a/fugue-high/src/eval/mod.rs
+++ b/fugue-high/src/eval/mod.rs
@@ -1,6 +1,4 @@
use fugue_bv::BitVec;
-
-use fugue_bytes::Endian;
use fugue_ir::disassembly::{Opcode, PCodeData};
use fugue_ir::{Address, AddressSpace, Translator, VarnodeData};
@@ -9,6 +7,8 @@ use thiserror::Error;
use crate::ir::Location;
use crate::lifter::Lifter;
+pub mod dummy;
+
pub mod fixed_state;
use self::fixed_state::FixedState;
@@ -47,84 +47,6 @@ pub trait EvaluatorContext {
fn write_vnd(&mut self, var: &VarnodeData, val: &BitVec) -> Result<(), EvaluatorError>;
}
-pub struct DummyContext {
- base: Address,
- endian: Endian,
- memory: FixedState,
- registers: FixedState,
- temporaries: FixedState,
-}
-
-impl DummyContext {
- pub fn new(lifter: &Lifter, base: impl Into, size: usize) -> Self {
- let t = lifter.translator();
-
- Self {
- base: base.into(),
- endian: if t.is_big_endian() {
- Endian::Big
- } else {
- Endian::Little
- },
- memory: FixedState::new(size),
- registers: FixedState::new(t.register_space_size()),
- temporaries: FixedState::new(t.unique_space_size()),
- }
- }
-
- fn translate(&self, addr: u64) -> Result {
- let addr = addr
- .checked_sub(self.base.into())
- .ok_or(EvaluatorError::state_with(
- "address translation out-of-bounds",
- ))?;
-
- Ok(addr as usize)
- }
-}
-
-impl EvaluatorContext for DummyContext {
- fn read_vnd(&mut self, var: &VarnodeData) -> Result {
- let spc = var.space();
- if spc.is_constant() {
- Ok(BitVec::from_u64(var.offset(), var.size() * 8))
- } else if spc.is_register() {
- self.registers
- .read_val_with(var.offset() as usize, var.size(), self.endian)
- .map_err(EvaluatorError::state)
- } else if spc.is_unique() {
- self.temporaries
- .read_val_with(var.offset() as usize, var.size(), self.endian)
- .map_err(EvaluatorError::state)
- } else {
- let addr = self.translate(var.offset())?;
- self.memory
- .read_val_with(addr, var.size(), self.endian)
- .map_err(EvaluatorError::state)
- }
- }
-
- fn write_vnd(&mut self, var: &VarnodeData, val: &BitVec) -> Result<(), EvaluatorError> {
- let spc = var.space();
- if spc.is_register() {
- self.registers
- .write_val_with(var.offset() as usize, val, self.endian)
- .map_err(EvaluatorError::state)
- } else if spc.is_unique() {
- self.temporaries
- .write_val_with(var.offset() as usize, val, self.endian)
- .map_err(EvaluatorError::state)
- } else if spc.is_default() {
- let addr = self.translate(var.offset())?;
- self.memory
- .write_val_with(addr, val, self.endian)
- .map_err(EvaluatorError::state)
- } else {
- panic!("cannot write to constant Varnode")
- }
- }
-}
-
pub struct Evaluator<'a, 'b, C>
where
C: EvaluatorContext,
@@ -169,9 +91,10 @@ where
pub fn step(
&mut self,
- loc: Location,
+ loc: impl Into,
operation: &PCodeData,
) -> Result {
+ let loc = loc.into();
match operation.opcode {
Opcode::Copy => {
let val = self.context.read_vnd(&operation.inputs[0])?;
diff --git a/fugue-high/src/ir.rs b/fugue-high/src/ir.rs
index 898d08a..04aaec1 100644
--- a/fugue-high/src/ir.rs
+++ b/fugue-high/src/ir.rs
@@ -84,10 +84,10 @@ impl Location {
}
}
-impl From for Location {
- fn from(address: Address) -> Self {
+impl From for Location where Address: From {
+ fn from(value: T) -> Self {
Self {
- address,
+ address: value.into(),
position: 0,
}
}
diff --git a/fugue-high/src/lib.rs b/fugue-high/src/lib.rs
index 4f4e2de..7afa53d 100644
--- a/fugue-high/src/lib.rs
+++ b/fugue-high/src/lib.rs
@@ -4,4 +4,5 @@ pub mod icfg;
pub mod ir;
pub mod language;
pub mod lifter;
+pub mod prelude;
pub mod util;
diff --git a/fugue-high/src/prelude.rs b/fugue-high/src/prelude.rs
new file mode 100644
index 0000000..a03d74f
--- /dev/null
+++ b/fugue-high/src/prelude.rs
@@ -0,0 +1,6 @@
+pub use fugue_bv::BitVec;
+pub use fugue_bytes::Endian;
+pub use fugue_ir::Address;
+
+pub use crate::language::{Language, LanguageBuilder};
+pub use crate::lifter::Lifter;