Skip to content

Commit

Permalink
add TranslationContext to simplify use
Browse files Browse the repository at this point in the history
  • Loading branch information
xorpse committed May 19, 2024
1 parent 1333ba7 commit e5b8ef6
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 159 deletions.
146 changes: 43 additions & 103 deletions fugue-core/src/lifter.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,30 @@
use std::cell::{Cell, Ref, RefCell};
use std::mem;

use fugue_ir::disassembly::lift::ArenaVec;
use fugue_ir::disassembly::{ContextDatabase, IRBuilderArena, PCodeData, ParserContext};
use fugue_ir::disassembly::PCodeRaw;
use fugue_ir::disassembly::{ContextDatabase, IRBuilderArena, PCodeData};
use fugue_ir::error::Error;
use fugue_ir::il::instruction::Instruction;
use fugue_ir::translator::TranslationContext;
use fugue_ir::{Address, Translator};

use ouroboros::self_referencing;

use crate::ir::{Insn, PCode};

#[self_referencing]
struct LifterInner<'a> {
translator: &'a Translator,
irb: IRBuilderArena,
ctx: ContextDatabase,
#[borrows(irb)]
#[covariant]
pctx: ParserContext<'a, 'this>,
}

#[derive(Clone)]
#[repr(transparent)]
pub struct Lifter<'a>(LifterInner<'a>);

impl<'a> Clone for Lifter<'a> {
fn clone(&self) -> Self {
// we recreate based on the current context database
let translator = *self.0.borrow_translator();
let ctx = self.0.borrow_ctx().clone();

Self::new_with(translator, ctx)
}

fn clone_from(&mut self, source: &Self) {
// we only need to copy the context database
let sctx = source.0.borrow_ctx().clone();
self.0.with_ctx_mut(|ctx| *ctx = sctx);
}
}
pub struct Lifter<'a>(TranslationContext<'a>);

impl<'a> Lifter<'a> {
pub fn new(translator: &'a Translator) -> Self {
Self::new_with(translator, translator.context_database())
Self(TranslationContext::new(translator))
}

pub fn new_with(translator: &'a Translator, ctx: ContextDatabase) -> Self {
let irb = IRBuilderArena::with_capacity(4096);

Self(LifterInner::new(translator, irb, ctx, |irb| {
ParserContext::empty(irb, translator.manager())
}))
Self(TranslationContext::new_with(translator, ctx))
}

pub fn irb(&self, size: usize) -> IRBuilderArena {
IRBuilderArena::with_capacity(size)
self.0.irb(size)
}

pub fn disassemble<'z>(
Expand All @@ -62,39 +33,23 @@ impl<'a> Lifter<'a> {
address: impl Into<Address>,
bytes: impl AsRef<[u8]>,
) -> Result<Insn<'z>, Error> {
let address = address.into();
let bytes = bytes.as_ref();

self.0.with_mut(|slf| {
let address = address.into();
let address_val = slf.translator.address(address.into());

let (mnemonic, operand_str, delay_slots, length) = slf.translator.disassemble_aux(
slf.ctx,
slf.pctx,
slf.irb,
address_val,
bytes,
|fmt, delay_slots, length| -> Result<_, Error> {
let mnemonic = fmt.mnemonic_str(irb);
let operand_str = fmt.operands_str(irb);

Ok((mnemonic, operand_str, delay_slots, length))
},
)?;

if length as usize > bytes.len() {
return Err(Error::Disassembly(
fugue_ir::disassembly::Error::InstructionResolution,
));
}

Ok(Insn {
address,
mnemonic,
operands: operand_str,
delay_slots: delay_slots as u8,
length: length as u8,
})
let Instruction {
mnemonic,
operands,
delay_slots,
length,
..
} = self.0.disassemble(irb, address, bytes)?;

Ok(Insn {
address,
mnemonic,
operands,
delay_slots: delay_slots as u8,
length: length as u8,
})
}

Expand All @@ -104,49 +59,34 @@ impl<'a> Lifter<'a> {
address: impl Into<Address>,
bytes: impl AsRef<[u8]>,
) -> Result<PCode<'z>, Error> {
let address = address.into();
let bytes = bytes.as_ref();

self.0.with_mut(|slf| {
let address = address.into();
let address_val = slf.translator.address(address.into());
let mut irbb = irb.builder(&slf.translator);

let pcode_raw = slf.translator.lift_with(
slf.ctx,
slf.pctx,
slf.irb,
&mut irbb,
address_val,
bytes,
)?;

if pcode_raw.length as usize > bytes.len() {
return Err(Error::Disassembly(
fugue_ir::disassembly::Error::InstructionResolution,
));
}

Ok(PCode {
address,
operations: pcode_raw.operations,
delay_slots: pcode_raw.delay_slots as u8,
length: pcode_raw.length as u8,
})
let PCodeRaw {
operations,
delay_slots,
length,
..
} = self.0.lift(irb, address, bytes)?;

Ok(PCode {
address,
operations,
delay_slots: delay_slots as u8,
length: length as u8,
})
}

pub fn translator(&self) -> &Translator {
self.0.borrow_translator()
self.0.translator()
}

pub fn reset(&mut self) {
let translator = *self.0.borrow_translator();
let mut ctx = translator.context_database();

// we preserve the old context database
self.0.with_ctx_mut(|old_ctx| mem::swap(old_ctx, &mut ctx));
pub fn context(&self) -> &ContextDatabase {
self.0.context()
}

*self = Self::new_with(translator, ctx);
pub fn reset(&mut self) {
self.0.reset();
}
}

Expand Down
2 changes: 2 additions & 0 deletions fugue-ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ fugue-bytes = { path = "../fugue-bytes", version = "0.3" }
iset = { version = "0.2", features = ["serde"] }
itertools = "0.12"
log = "0.4"
ouroboros = "0.18"
roxmltree = "0.19"
serde = { version = "1", features = ["derive", "rc"] }
smallvec = { version = "1", features = ["serde"] }
stack-map = "1.0"
thiserror = "1"
ustr = { version = "1.0", features = ["serde"] }
walkdir = "2"
62 changes: 27 additions & 35 deletions fugue-ir/src/disassembly/lift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::ops::Deref;
use std::sync::Arc;

use ahash::AHashMap as Map;
use stack_map::StackMap;
use ustr::Ustr;

use crate::address::AddressValue;
Expand All @@ -16,7 +17,7 @@ use crate::disassembly::{Error, ParserContext, ParserWalker};
use crate::float_format::FloatFormat;
use crate::space::AddressSpace;
use crate::space_manager::SpaceManager;
use crate::Translator;
use crate::translator::{Translator, MAX_DELAY_SLOTS};

pub use bumpalo::collections::String as ArenaString;
pub use bumpalo::collections::Vec as ArenaVec;
Expand Down Expand Up @@ -349,14 +350,6 @@ impl IRBuilderArena {
&self.0
}

pub fn builder<'b, 'z>(&'z self, translator: &'b Translator) -> IRBuilderBase<'b, 'z> {
IRBuilderBase::empty(
&self,
translator.manager(),
translator.unique_mask(),
)
}

pub fn boxed<'z, T>(&'z self, val: T) -> ArenaRef<'z, T> {
ArenaRef::new_in(self, val)
}
Expand All @@ -382,34 +375,31 @@ impl Deref for IRBuilderArena {
}
}

pub struct IRBuilderBase<'b, 'z> {
pub struct IRBuilderBase<'b, 'cz> {
const_space: &'b AddressSpace,
unique_mask: u64,

alloc: &'z IRBuilderArena,

label_base: usize,
label_count: usize,
label_refs: ArenaVec<'z, RelativeRecord>,
labels: ArenaVec<'z, u64>,
label_refs: ArenaVec<'cz, RelativeRecord>,
labels: ArenaVec<'cz, u64>,

manager: &'b SpaceManager,
}

impl<'b, 'z> IRBuilderBase<'b, 'z> {
impl<'b, 'cz> IRBuilderBase<'b, 'cz> {
pub fn empty(
alloc: &'z IRBuilderArena,
alloc_inner: &'cz IRBuilderArena,
manager: &'b SpaceManager,
unique_mask: u64,
) -> Self {
Self {
const_space: manager.constant_space_ref(),
unique_mask,
alloc,
label_base: 0,
label_count: 0,
labels: ArenaVec::with_capacity_in(16, alloc.inner()),
label_refs: ArenaVec::with_capacity_in(16, alloc.inner()),
labels: ArenaVec::with_capacity_in(16, alloc_inner.inner()),
label_refs: ArenaVec::with_capacity_in(16, alloc_inner.inner()),
manager,
}
}
Expand All @@ -421,6 +411,7 @@ impl<'b, 'z> IRBuilderBase<'b, 'z> {
self.label_refs.clear();
}

/*
pub(crate) fn arena(&self) -> &'z Arena {
self.alloc
}
Expand All @@ -432,13 +423,15 @@ impl<'b, 'z> IRBuilderBase<'b, 'z> {
pub fn alloc_vec<T>(&self) -> ArenaVec<'z, T> {
ArenaVec::new_in(self.alloc)
}
*/
}

pub struct IRBuilder<'b, 'c, 'cz, 'z> {
base: &'c mut IRBuilderBase<'b, 'z>,
base: &'c mut IRBuilderBase<'b, 'cz>,
arena: &'z IRBuilderArena,
unique_offset: u64,
issued: ArenaVec<'z, PCodeData<'z>>,
delay_contexts: Map<AddressValue, &'c mut ParserContext<'b, 'cz>>,
delay_contexts: StackMap<AddressValue, &'c mut ParserContext<'b, 'cz>, MAX_DELAY_SLOTS>,
walker: ParserWalker<'b, 'c, 'cz>,
}

Expand Down Expand Up @@ -466,7 +459,7 @@ pub struct IRBuilder<'b, 'c> {
*/

impl<'b, 'c, 'cz, 'z> Deref for IRBuilder<'b, 'c, 'cz, 'z> {
type Target = &'c mut IRBuilderBase<'b, 'z>;
type Target = &'c mut IRBuilderBase<'b, 'cz>;

fn deref(&self) -> &Self::Target {
&self.base
Expand All @@ -475,20 +468,19 @@ impl<'b, 'c, 'cz, 'z> Deref for IRBuilder<'b, 'c, 'cz, 'z> {

impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> {
pub fn new(
base: &'c mut IRBuilderBase<'b, 'z>,
base: &'c mut IRBuilderBase<'b, 'cz>,
arena: &'z IRBuilderArena,
walker: ParserWalker<'b, 'c, 'cz>,
delay_contexts: &'c mut Map<AddressValue, ParserContext<'b, 'cz>>,
delay_contexts: StackMap<AddressValue, &'c mut ParserContext<'b, 'cz>, MAX_DELAY_SLOTS>,
) -> Self {
base.reinitialise();
Self {
unique_offset: (walker.address().offset() & base.unique_mask) >> 4,
issued: ArenaVec::with_capacity_in(16, &base.alloc),
issued: ArenaVec::with_capacity_in(16, arena),
base,
arena,
walker,
delay_contexts: delay_contexts
.iter_mut()
.map(|(k, v)| (k.clone(), v))
.collect(),
delay_contexts,
}
}

Expand Down Expand Up @@ -686,7 +678,7 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> {

pub fn dump(&mut self, op: &'b OpTpl) -> Result<(), Error> {
let input_count = op.input_count();
let mut pcode = PCodeData::new_in(&self.base.arena(), op.opcode(), input_count);
let mut pcode = PCodeData::new_in(self.arena, op.opcode(), input_count);

for i in 0..input_count {
let input = op.input(i);
Expand All @@ -696,7 +688,7 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> {
let index = VarnodeData::new(self.const_space, spc.index() as u64, 0);
self.issued.push(PCodeData {
opcode: Opcode::Load,
inputs: arena_vec![in self.base.alloc; index, ptr],
inputs: arena_vec![in self.arena; index, ptr],
output: Some(varnode.clone()),
});
pcode.inputs.push(varnode);
Expand All @@ -720,7 +712,7 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> {
let index = VarnodeData::new(self.const_space, spc.index() as u64, 0);
self.issued.push(PCodeData {
opcode: Opcode::Store,
inputs: arena_vec![in self.base.alloc; index, ptr, outp],
inputs: arena_vec![in self.arena; index, ptr, outp],
output: None,
})
}
Expand Down Expand Up @@ -782,8 +774,8 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> {
)));
}
Some(label) => {
let res =
label.wrapping_sub(rel.instruction as u64) & bits::calculate_mask(varnode.size());
let res = label.wrapping_sub(rel.instruction as u64)
& bits::calculate_mask(varnode.size());
varnode.offset = res;
}
}
Expand All @@ -796,7 +788,7 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> {
let mut slf = self;
slf.walker.base_state();

let mut operations = ArenaVec::new_in(&slf.base.alloc);
let mut operations = ArenaVec::new_in(slf.arena);
swap(&mut slf.issued, &mut operations);

PCodeRaw {
Expand Down
1 change: 0 additions & 1 deletion fugue-ir/src/disassembly/walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ impl<'b, 'z> ParserContext<'b, 'z> {

pub fn reinitialise(
&mut self,
_arena: &'z IRBuilderArena,
context_db: &ContextDatabase,
address: AddressValue,
buffer: &[u8],
Expand Down
Loading

0 comments on commit e5b8ef6

Please sign in to comment.