Skip to content

Commit

Permalink
ARM decoder test with mixed decoder/lifter
Browse files Browse the repository at this point in the history
  • Loading branch information
xorpse committed Mar 9, 2024
1 parent e68e382 commit 5767eed
Show file tree
Hide file tree
Showing 7 changed files with 370 additions and 181 deletions.
5 changes: 3 additions & 2 deletions fugue-high/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
bitflags = "2"
fugue-arch = { version = "0.3", path = "../fugue-arch" }
fugue-bv = { version = "0.3", path = "../fugue-bv" }
fugue-ir = { version = "0.3", path = "../fugue-ir" }
nom = "7"
ouroboros = "0.18"
Expand All @@ -15,9 +16,9 @@ serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
static_init = "1"
thiserror = "1"
yaxpeax-arch = { version = "0.2", default-features = false }
yaxpeax-arm = "0.2"

[dev-dependencies]
anyhow = "1"
env_logger = "0.10"
yaxpeax-arch = { version = "0.2", default-features = false }
yaxpeax-arm = "0.2"
98 changes: 98 additions & 0 deletions fugue-high/src/arch/arm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use std::cell::{Cell, RefCell};

use fugue_ir::disassembly::IRBuilderArena;
use fugue_ir::Address;

use thiserror::Error;

use yaxpeax_arch::*;
use yaxpeax_arm::armv7::{Opcode, Operand, Reg};

pub use yaxpeax_arm::armv7::{
DecodeError as ARMDecoderError, InstDecoder as ARMInstDecoder, Instruction as ARMInstruction,
};

use crate::lifter::{InsnLifter, LiftedInsn, LiftedInsnProperties, Lifter, PCode};

pub struct ARMInsnLifter {
decoder: ARMInstDecoder,
}

#[derive(Debug, Error)]
pub enum ARMLifterError {
#[error(transparent)]
Decoder(#[from] ARMDecoderError),
#[error(transparent)]
Lifter(#[from] fugue_ir::error::Error),
}

impl ARMInsnLifter {
pub fn new() -> Self {
Self::new_with(ARMInstDecoder::armv7())
}

pub fn new_with(decoder: ARMInstDecoder) -> Self {
Self { decoder }
}
}

fn should_lift(insn: &ARMInstruction) -> bool {
let pc = Reg::from_u8(15);

match insn.opcode {
Opcode::B
| Opcode::BL
| Opcode::BX
| Opcode::CBZ
| Opcode::CBNZ
| Opcode::SVC
| Opcode::BKPT => true,
Opcode::MOV => insn.operands[0] == Operand::Reg(pc),
_ => false,
}
}

impl<'a> InsnLifter<'a, ARMInstruction> for ARMInsnLifter {
type Error = ARMLifterError;

fn properties<'b>(
&mut self,
lifter: &mut Lifter,
irb: &'a IRBuilderArena,
address: Address,
bytes: &'b [u8],
) -> Result<LiftedInsn<'a, 'b, ARMInstruction>, Self::Error> {
let mut reader = yaxpeax_arch::U8Reader::new(bytes);
let insn = self.decoder.decode(&mut reader)?;
let size = insn.len().to_const() as u8;

if should_lift(&insn) {
let PCode {
address,
operations,
delay_slots,
length,
} = lifter.lift(irb, address, bytes)?;

Ok(LiftedInsn {
address,
bytes,
properties: Cell::new(LiftedInsnProperties::default()),
operations: RefCell::new(Some(operations)),
delay_slots,
length,
data: insn,
})
} else {
Ok(LiftedInsn {
address,
bytes,
properties: Cell::new(LiftedInsnProperties::default()),
operations: RefCell::new(None),
delay_slots: 0,
length: size,
data: insn,
})
}
}
}
1 change: 1 addition & 0 deletions fugue-high/src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod arm;
91 changes: 91 additions & 0 deletions fugue-high/src/eval/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::borrow::Cow;
use std::marker::PhantomData;

use fugue_bv::BitVec;

use fugue_ir::disassembly::{IRBuilderArena, Opcode, PCodeData};
use fugue_ir::il::Location;
use fugue_ir::{Address, VarnodeData};

use thiserror::Error;

use crate::lifter::{Lifter, PCode};

#[derive(Debug, Error)]
pub enum EvaluatorError {
#[error("{0}")]
Lift(fugue_ir::error::Error),
}

pub trait EvaluatorContext<'ir> {
fn read_vnd(&mut self, var: &VarnodeData) -> Result<BitVec, EvaluatorError>;
fn write_vnd(&mut self, var: &VarnodeData, val: &BitVec) -> Result<BitVec, EvaluatorError>;

fn fetch(&mut self, addr: Address) -> Result<Vec<PCodeData<'ir>>, EvaluatorError>;
}

pub struct DummyContext<'a, 'ir> {
lifter: Lifter<'a>,
irb: &'ir IRBuilderArena,
}

impl<'a, 'ir> EvaluatorContext<'ir> for DummyContext<'a, 'ir> {
fn read_vnd(&mut self, var: &VarnodeData) -> Result<BitVec, EvaluatorError> {
todo!()
}

fn write_vnd(&mut self, var: &VarnodeData, val: &BitVec) -> Result<BitVec, EvaluatorError> {
todo!()
}

fn fetch(&mut self, addr: Address) -> Result<Vec<PCodeData<'ir>>, EvaluatorError> {
self.lifter
.lift(self.irb, addr, &[])
.map_err(EvaluatorError::Lift)
}
}

pub struct Evaluator<'a, 'ir, C>
where
C: EvaluatorContext<'ir>,
{
context: &'a mut C,
step_state: Option<StepState>,
_marker: PhantomData<fn() -> &'ir [PCodeData<'ir>]>,
}

struct StepState {
location: Location,
}

impl<'a, 'ir, C> Evaluator<'a, 'ir, C>
where
C: EvaluatorContext<'ir>,
{
pub fn new(context: &'a mut C) -> Self {
Self {
context,
step_state: None,
}
}

fn fetch_next(data: PCodeData) {}

fn fetch_operation(
context: &mut C,
step_state: &mut Option<StepState>,
location: Location,
) -> Result<Opcode, EvaluatorError> {
todo!()
}

pub fn step_from(&mut self, location: impl Into<Location>) -> Result<(), EvaluatorError> {
let location = location.into();

// 1. obtain next operation

// 2. evaluate the operation

Ok(())
}
}
Loading

0 comments on commit 5767eed

Please sign in to comment.