diff options
| author | Ryan Snyder <ryan@vector35.com> | 2021-01-21 18:27:48 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:06:55 +0000 |
| commit | d3140edec185f47235b9e4642bdd56d6c585a341 (patch) | |
| tree | a61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/llil/instruction.rs | |
| parent | c0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (diff) | |
This is a combination of 23 commits, the work of Ryan Snyder:
Initial fresh repo
Add support for recent calling convention API updates and folds the binaryninjacore-sys crate directly into this one.
Add support for auto function analysis suppression
Finish moving binaryninjacore-sys back into this crate
Update for Symbol/Segment core API changes
Update for Symbol API cleanup
api: advance submodule reference, support Token changes
arch/lifting: support for flags in custom architectures
arch/lifting: support default flag write behaviors, handle more ops
build: enable headless binary support on MacOS via evil hack
bv: add BinaryView wrapper support, remove wrong comment
api: update to latest binja dev branch support
deps: bump dep versions
rust: bump to 2018 edition
api: bump to avoid cargo submodule brokenness
build: improve binaryninja path detection; enable linux linkhack
bv: stub for bv load settings
arch: fix flag related crash, minor llil update
api: update for recent changes
macos: disable linkhack briefly
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>), +} |
