diff --git a/fugue-high/src/arch/arm.rs b/fugue-high/src/arch/arm.rs
index 1ddbcc1..ebf0c5a 100644
--- a/fugue-high/src/arch/arm.rs
+++ b/fugue-high/src/arch/arm.rs
@@ -12,7 +12,8 @@ pub use yaxpeax_arm::armv7::{
DecodeError as ARMDecoderError, InstDecoder as ARMInstDecoder, Instruction as ARMInstruction,
};
-use crate::lifter::{InsnLifter, LiftedInsn, LiftedInsnProperties, Lifter, PCode};
+use crate::ir::PCode;
+use crate::lifter::{InsnLifter, LiftedInsn, LiftedInsnProperties, Lifter};
pub struct ARMInsnLifter {
decoder: ARMInstDecoder,
diff --git a/fugue-high/src/eval/mod.rs b/fugue-high/src/eval/mod.rs
index 65b88a0..a770bf3 100644
--- a/fugue-high/src/eval/mod.rs
+++ b/fugue-high/src/eval/mod.rs
@@ -1,11 +1,11 @@
use fugue_bv::BitVec;
use fugue_ir::disassembly::{Opcode, PCodeData};
-use fugue_ir::il::Location;
use fugue_ir::{Address, AddressSpace, Translator, VarnodeData};
use thiserror::Error;
+use crate::ir::Location;
use crate::lifter::Lifter;
#[derive(Debug, Error)]
@@ -65,10 +65,12 @@ where
translator: &'a Translator,
}
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EvaluatorTarget {
Branch(Location),
+ Call(Location),
Fall,
+ Return(Location),
}
fn bv2addr(bv: BitVec) -> Result
{
@@ -95,7 +97,11 @@ where
}
}
- pub fn step(&mut self, operation: &PCodeData) -> Result {
+ pub fn step(
+ &mut self,
+ loc: Location,
+ operation: &PCodeData,
+ ) -> Result {
match operation.opcode {
Opcode::Copy => {
let val = self.context.read_vnd(&operation.inputs[0])?;
@@ -240,12 +246,72 @@ where
Opcode::PopCount => self.lift_unsigned_int1(operation, |val| {
Ok(BitVec::from_u32(val.count_ones(), val.bits()))
})?,
+ Opcode::Subpiece => self.subpiece(operation)?,
+ Opcode::Branch => {
+ let locn =
+ Location::absolute_from(loc.address(), operation.inputs[0], loc.position());
+ return Ok(EvaluatorTarget::Branch(locn));
+ }
+ Opcode::CBranch => {
+ if self.read_bool(&operation.inputs[1])? {
+ let locn =
+ Location::absolute_from(loc.address(), operation.inputs[0], loc.position());
+ return Ok(EvaluatorTarget::Branch(locn));
+ }
+ }
+ Opcode::IBranch => {
+ let addr = self.read_addr(&operation.inputs[0])?;
+ return Ok(EvaluatorTarget::Branch(addr.into()));
+ }
+ Opcode::Call => {
+ let locn =
+ Location::absolute_from(loc.address(), operation.inputs[0], loc.position());
+ return Ok(EvaluatorTarget::Call(locn));
+ }
+ Opcode::ICall => {
+ let addr = self.read_addr(&operation.inputs[0])?;
+ return Ok(EvaluatorTarget::Call(addr.into()));
+ }
+ Opcode::Return => {
+ let addr = self.read_addr(&operation.inputs[0])?;
+ return Ok(EvaluatorTarget::Return(addr.into()));
+ }
op => return Err(EvaluatorError::Unsupported(op)),
}
Ok(EvaluatorTarget::Fall)
}
+ fn subpiece(&mut self, operation: &PCodeData) -> Result<(), EvaluatorError> {
+ let src = self.context.read_vnd(&operation.inputs[0])?;
+ let src_size = src.bits();
+
+ let off = operation.inputs[1].offset() as usize * 8;
+
+ let dst = operation.output.as_ref().unwrap();
+ let dst_size = dst.size() * 8;
+
+ let trun_size = src_size.saturating_sub(off);
+ let trun = if dst_size > trun_size {
+ // extract high + expand
+ if trun_size >= src_size {
+ src
+ } else {
+ src >> (src_size - trun_size) as u32
+ }
+ .unsigned()
+ .cast(trun_size)
+ .cast(dst_size)
+ } else {
+ // extract
+ if off > 0 { src >> off as u32 } else { src }
+ .unsigned()
+ .cast(dst_size)
+ };
+
+ self.assign(dst, trun)
+ }
+
fn lift_signed_int2(&mut self, operation: &PCodeData, op: F) -> Result<(), EvaluatorError>
where
F: FnOnce(BitVec, BitVec) -> Result,
@@ -337,6 +403,11 @@ where
self.assign(dst, val.cast(dst.size() * 8))
}
+ fn read_bool(&mut self, var: &VarnodeData) -> Result {
+ let val = self.context.read_vnd(var)?;
+ Ok(!val.is_zero())
+ }
+
fn read_addr(&mut self, var: &VarnodeData) -> Result {
bv2addr(self.context.read_vnd(var)?)
}
diff --git a/fugue-high/src/ir.rs b/fugue-high/src/ir.rs
new file mode 100644
index 0000000..898d08a
--- /dev/null
+++ b/fugue-high/src/ir.rs
@@ -0,0 +1,151 @@
+use std::fmt;
+use std::ops::Add;
+
+use fugue_ir::disassembly::lift::{ArenaString, ArenaVec};
+use fugue_ir::disassembly::PCodeData;
+use fugue_ir::{Address, VarnodeData};
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Location {
+ pub address: Address,
+ pub position: u32,
+}
+
+impl Default for Location {
+ fn default() -> Self {
+ Address::from(0u32).into()
+ }
+}
+
+impl fmt::Display for Location {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}.{}", self.address, self.position)
+ }
+}
+
+impl Add for Location {
+ type Output = Self;
+
+ fn add(self, rhs: u32) -> Self::Output {
+ Self {
+ position: self.position + rhs,
+ ..self
+ }
+ }
+}
+
+impl Add for Location {
+ type Output = Self;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ Self {
+ position: self.position + rhs as u32,
+ ..self
+ }
+ }
+}
+
+impl Location {
+ pub fn new(address: impl Into, position: u32) -> Location {
+ Self {
+ address: address.into(),
+ position,
+ }
+ }
+
+ pub fn address(&self) -> Address {
+ self.address
+ }
+
+ pub fn position(&self) -> u32 {
+ self.position
+ }
+
+ pub(super) fn absolute_from(base: Address, address: VarnodeData, position: u32) -> Self {
+ if !address.space().is_constant() {
+ return Self::new(address.offset(), 0); // position);
+ }
+
+ let offset = address.offset() as i64;
+ let position = if offset.is_negative() {
+ position
+ .checked_sub(offset.abs() as u32)
+ .expect("negative offset from position in valid range")
+ } else {
+ position
+ .checked_add(offset as u32)
+ .expect("positive offset from position in valid range")
+ };
+
+ Self {
+ address: base.into(),
+ position,
+ }
+ }
+}
+
+impl From for Location {
+ fn from(address: Address) -> Self {
+ Self {
+ address,
+ position: 0,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Insn<'a> {
+ pub address: Address,
+ pub mnemonic: ArenaString<'a>,
+ pub operands: ArenaString<'a>,
+ pub delay_slots: u8,
+ pub length: u8,
+}
+
+impl<'a> Insn<'a> {
+ pub fn address(&self) -> Address {
+ self.address
+ }
+
+ pub fn mnemonic(&self) -> &str {
+ &self.mnemonic
+ }
+
+ pub fn operands(&self) -> &str {
+ &self.operands
+ }
+
+ pub fn delay_slots(&self) -> usize {
+ self.delay_slots as _
+ }
+
+ pub fn len(&self) -> usize {
+ self.length as _
+ }
+}
+
+#[derive(Debug)]
+pub struct PCode<'a> {
+ pub address: Address,
+ pub operations: ArenaVec<'a, PCodeData<'a>>,
+ pub delay_slots: u8,
+ pub length: u8,
+}
+
+impl<'a> PCode<'a> {
+ pub fn address(&self) -> Address {
+ self.address
+ }
+
+ pub fn operations(&self) -> &[PCodeData<'a>] {
+ &self.operations
+ }
+
+ pub fn delay_slots(&self) -> usize {
+ self.delay_slots as _
+ }
+
+ pub fn len(&self) -> usize {
+ self.length as _
+ }
+}
diff --git a/fugue-high/src/lib.rs b/fugue-high/src/lib.rs
index c42c5a0..4f4e2de 100644
--- a/fugue-high/src/lib.rs
+++ b/fugue-high/src/lib.rs
@@ -1,6 +1,7 @@
pub mod arch;
pub mod eval;
pub mod icfg;
+pub mod ir;
pub mod language;
pub mod lifter;
pub mod util;
diff --git a/fugue-high/src/lifter.rs b/fugue-high/src/lifter.rs
index 5441033..8d3a6c9 100644
--- a/fugue-high/src/lifter.rs
+++ b/fugue-high/src/lifter.rs
@@ -1,69 +1,14 @@
use std::cell::{Cell, Ref, RefCell};
use std::mem;
-use fugue_ir::disassembly::lift::{ArenaString, ArenaVec};
+use fugue_ir::disassembly::lift::ArenaVec;
use fugue_ir::disassembly::{ContextDatabase, IRBuilderArena, PCodeData, ParserContext};
use fugue_ir::error::Error;
use fugue_ir::{Address, Translator};
use ouroboros::self_referencing;
-#[derive(Debug)]
-pub struct Insn<'a> {
- pub address: Address,
- pub mnemonic: ArenaString<'a>,
- pub operands: ArenaString<'a>,
- pub delay_slots: u8,
- pub length: u8,
-}
-
-impl<'a> Insn<'a> {
- pub fn address(&self) -> Address {
- self.address
- }
-
- pub fn mnemonic(&self) -> &str {
- &self.mnemonic
- }
-
- pub fn operands(&self) -> &str {
- &self.operands
- }
-
- pub fn delay_slots(&self) -> usize {
- self.delay_slots as _
- }
-
- pub fn len(&self) -> usize {
- self.length as _
- }
-}
-
-#[derive(Debug)]
-pub struct PCode<'a> {
- pub address: Address,
- pub operations: ArenaVec<'a, PCodeData<'a>>,
- pub delay_slots: u8,
- pub length: u8,
-}
-
-impl<'a> PCode<'a> {
- pub fn address(&self) -> Address {
- self.address
- }
-
- pub fn operations(&self) -> &[PCodeData<'a>] {
- &self.operations
- }
-
- pub fn delay_slots(&self) -> usize {
- self.delay_slots as _
- }
-
- pub fn len(&self) -> usize {
- self.length as _
- }
-}
+use crate::ir::{Insn, PCode};
#[self_referencing]
struct LifterInner<'a> {
@@ -373,4 +318,3 @@ impl<'a> InsnLifter<'a> for DefaultInsnLifter {
})
}
}
-