diff options
Diffstat (limited to 'rust/src/llil/instruction.rs')
| -rw-r--r-- | rust/src/llil/instruction.rs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/rust/src/llil/instruction.rs b/rust/src/llil/instruction.rs new file mode 100644 index 00000000..4d1554df --- /dev/null +++ b/rust/src/llil/instruction.rs @@ -0,0 +1,175 @@ +use binaryninjacore_sys::BNGetLowLevelILByIndex; +use binaryninjacore_sys::BNGetLowLevelILIndexForInstruction; +use binaryninjacore_sys::BNLowLevelILInstruction; + +use std::marker::PhantomData; + +use super::*; +use super::operation; +use super::operation::Operation; + +use crate::architecture::Architecture; + +pub struct Instruction<'func, A, M, F> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + pub(crate) function: &'func Function<A, M, F>, + pub(crate) instr_idx: usize, +} + +fn common_info<'func, A, M, F>(function: &'func Function<A, M, F>, op: BNLowLevelILInstruction) + -> Option<InstrInfo<'func, A, M, F>> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + use binaryninjacore_sys::BNLowLevelILOperation::*; + + match op.operation { + LLIL_NOP => InstrInfo::Nop(Operation::new(function, op)).into(), + LLIL_JUMP => InstrInfo::Jump(Operation::new(function, op)).into(), + LLIL_JUMP_TO => InstrInfo::JumpTo(Operation::new(function, op)).into(), + LLIL_RET => InstrInfo::Ret(Operation::new(function, op)).into(), + LLIL_NORET => InstrInfo::NoRet(Operation::new(function, op)).into(), + LLIL_IF => InstrInfo::If(Operation::new(function, op)).into(), + LLIL_GOTO => InstrInfo::Goto(Operation::new(function, op)).into(), + LLIL_BP => InstrInfo::Bp(Operation::new(function, op)).into(), + LLIL_TRAP => InstrInfo::Trap(Operation::new(function, op)).into(), + LLIL_UNDEF => InstrInfo::Undef(Operation::new(function, op)).into(), + _ => None, + } +} + +use super::VisitorAction; + +macro_rules! visit { + ($f:expr, $($e:expr),*) => { + if let VisitorAction::Halt = $f($($e,)*) { + return VisitorAction::Halt; + } + } +} + +fn common_visit<'func, A, M, F, CB>(info: &InstrInfo<'func, A, M, F>, f: &mut CB) + -> VisitorAction +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + CB: FnMut(&Expression<'func, A, M, F, ValueExpr>) -> VisitorAction, +{ + use self::InstrInfo::*; + + match *info { + Jump(ref op) => visit!(f, &op.target()), + JumpTo(ref op) => visit!(f, &op.target()), + Ret(ref op) => visit!(f, &op.target()), + If(ref op) => visit!(f, &op.condition()), + Value(ref e, _) => visit!(f, e), + _ => {}, + }; + + VisitorAction::Sibling +} + +impl<'func, A, M, V> Instruction<'func, A, M, NonSSA<V>> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub fn info(&self) -> InstrInfo<'func, A, M, NonSSA<V>> { + use binaryninjacore_sys::BNLowLevelILOperation::*; + + let expr_idx = unsafe { BNGetLowLevelILIndexForInstruction(self.function.handle, self.instr_idx) }; + let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, expr_idx) }; + + match op.operation { + LLIL_SET_REG => InstrInfo::SetReg(Operation::new(self.function, op)), + LLIL_SET_REG_SPLIT => InstrInfo::SetRegSplit(Operation::new(self.function, op)), + LLIL_SET_FLAG => InstrInfo::SetFlag(Operation::new(self.function, op)), + LLIL_STORE => InstrInfo::Store(Operation::new(self.function, op)), + LLIL_PUSH => InstrInfo::Push(Operation::new(self.function, op)), + LLIL_CALL | + LLIL_CALL_STACK_ADJUST => InstrInfo::Call(Operation::new(self.function, op)), + LLIL_SYSCALL => InstrInfo::Syscall(Operation::new(self.function, op)), + _ => { + common_info(self.function, op).unwrap_or_else(|| { + // Hopefully this is a bare value. If it isn't (expression + // from wrong function form or similar) it won't really cause + // any problems as it'll come back as undefined when queried. + let expr = Expression { + function: self.function, + expr_idx: expr_idx, + _ty: PhantomData, + }; + + let info = unsafe { expr.info_from_op(op) }; + + InstrInfo::Value(expr, info) + }) + } + } + } + + pub fn visit_tree<F>(&self, f: &mut F) -> VisitorAction + where + F: FnMut(&Expression<'func, A, M, NonSSA<V>, ValueExpr>, &ExprInfo<'func, A, M, NonSSA<V>>) -> VisitorAction, + { + use self::InstrInfo::*; + let info = self.info(); + + let fb = &mut |e: &Expression<'func, A, M, NonSSA<V>, ValueExpr>| e.visit_tree(f); + + match info { + SetReg(ref op) => visit!(fb, &op.source_expr()), + SetRegSplit(ref op) => visit!(fb, &op.source_expr()), + SetFlag(ref op) => visit!(fb, &op.source_expr()), + Store(ref op) => { + visit!(fb, &op.dest_mem_expr()); + visit!(fb, &op.source_expr()); + } + Push(ref op) => visit!(fb, &op.operand()), + Call(ref op) => visit!(fb, &op.target()), + _ => visit!(common_visit, &info, fb), + } + + VisitorAction::Sibling + } +} + +pub enum InstrInfo<'func, A, M, F> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + Nop(Operation<'func, A, M, F, operation::NoArgs>), + SetReg(Operation<'func, A, M, F, operation::SetReg>), + SetRegSplit(Operation<'func, A, M, F, operation::SetRegSplit>), + SetFlag(Operation<'func, A, M, F, operation::SetFlag>), + Store(Operation<'func, A, M, F, operation::Store>), + Push(Operation<'func, A, M, F, operation::UnaryOp>), // TODO needs a real op + + Jump(Operation<'func, A, M, F, operation::Jump>), + JumpTo(Operation<'func, A, M, F, operation::JumpTo>), + + Call(Operation<'func, A, M, F, operation::Call>), + + Ret(Operation<'func, A, M, F, operation::Ret>), + NoRet(Operation<'func, A, M, F, operation::NoArgs>), + + If(Operation<'func, A, M, F, operation::If>), + Goto(Operation<'func, A, M, F, operation::Goto>), + + Syscall(Operation<'func, A, M, F, operation::Syscall>), + Bp(Operation<'func, A, M, F, operation::NoArgs>), + Trap(Operation<'func, A, M, F, operation::Trap>), + Undef(Operation<'func, A, M, F, operation::NoArgs>), + + Value(Expression<'func, A, M, F, ValueExpr>, ExprInfo<'func, A, M, F>), +} |
