diff options
Diffstat (limited to 'rust/src/llil')
| -rw-r--r-- | rust/src/llil/block.rs | 103 | ||||
| -rw-r--r-- | rust/src/llil/expression.rs | 851 | ||||
| -rw-r--r-- | rust/src/llil/function.rs | 255 | ||||
| -rw-r--r-- | rust/src/llil/instruction.rs | 209 | ||||
| -rw-r--r-- | rust/src/llil/lifting.rs | 1492 | ||||
| -rw-r--r-- | rust/src/llil/mod.rs | 95 | ||||
| -rw-r--r-- | rust/src/llil/operation.rs | 825 |
7 files changed, 0 insertions, 3830 deletions
diff --git a/rust/src/llil/block.rs b/rust/src/llil/block.rs deleted file mode 100644 index d904d2d8..00000000 --- a/rust/src/llil/block.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::ops::Range; - -use crate::architecture::Architecture; -use crate::basicblock::{BasicBlock, BlockContext}; - -use super::*; - -pub struct BlockIter<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - function: &'func Function<A, M, F>, - range: Range<u64>, -} - -impl<'func, A, M, F> Iterator for BlockIter<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - type Item = Instruction<'func, A, M, F>; - - fn next(&mut self) -> Option<Self::Item> { - self.range.next().map(|i| Instruction { - function: self.function, - instr_idx: i as usize, - }) - } -} - -pub struct Block<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub(crate) function: &'func Function<A, M, F>, -} - -impl<'func, A, M, F> fmt::Debug for Block<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "llil_bb {:?}", self.function) - } -} - -impl<'func, A, M, F> BlockContext for Block<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - type Iter = BlockIter<'func, A, M, F>; - type Instruction = Instruction<'func, A, M, F>; - - fn start(&self, block: &BasicBlock<Self>) -> Instruction<'func, A, M, F> { - Instruction { - function: self.function, - instr_idx: block.raw_start() as usize, - } - } - - fn iter(&self, block: &BasicBlock<Self>) -> BlockIter<'func, A, M, F> { - BlockIter { - function: self.function, - range: block.raw_start()..block.raw_end(), - } - } -} - -impl<'func, A, M, F> Clone for Block<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - fn clone(&self) -> Self { - Block { - function: self.function, - } - } -} diff --git a/rust/src/llil/expression.rs b/rust/src/llil/expression.rs deleted file mode 100644 index f04368a7..00000000 --- a/rust/src/llil/expression.rs +++ /dev/null @@ -1,851 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use binaryninjacore_sys::BNGetLowLevelILByIndex; -use binaryninjacore_sys::BNLowLevelILInstruction; - -use std::fmt; -use std::marker::PhantomData; - -use super::operation; -use super::operation::Operation; -use super::*; - -use crate::architecture::Architecture; -use crate::architecture::RegisterInfo; - -// used as a marker for Expressions that can produce a value -#[derive(Copy, Clone, Debug)] -pub struct ValueExpr; - -// used as a marker for Expressions that can not produce a value -#[derive(Copy, Clone, Debug)] -pub struct VoidExpr; - -pub trait ExpressionResultType: 'static {} -impl ExpressionResultType for ValueExpr {} -impl ExpressionResultType for VoidExpr {} - -pub struct Expression<'func, A, M, F, R> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, - R: ExpressionResultType, -{ - pub(crate) function: &'func Function<A, M, F>, - pub(crate) expr_idx: usize, - - // tag the 'return' type of this expression - pub(crate) _ty: PhantomData<R>, -} - -impl<'func, A, M, F, R> Expression<'func, A, M, F, R> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, - R: ExpressionResultType, -{ - pub(crate) fn new(function: &'func Function<A, M, F>, expr_idx: usize) -> Self { - Self { - function, - expr_idx, - _ty: PhantomData, - } - } - - pub fn index(&self) -> usize { - self.expr_idx - } -} - -impl<'func, A, M, V> fmt::Debug for Expression<'func, A, M, NonSSA<V>, ValueExpr> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let op_info = self.info(); - write!(f, "<expr {}: {:?}>", self.expr_idx, op_info) - } -} - -fn common_info<'func, A, M, F>( - function: &'func Function<A, M, F>, - op: BNLowLevelILInstruction, -) -> ExprInfo<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - use binaryninjacore_sys::BNLowLevelILOperation::*; - - match op.operation { - LLIL_CONST => ExprInfo::Const(Operation::new(function, op)), - LLIL_CONST_PTR => ExprInfo::ConstPtr(Operation::new(function, op)), - - LLIL_EXTERN_PTR => ExprInfo::ExternPtr(Operation::new(function, op)), - - LLIL_ADD => ExprInfo::Add(Operation::new(function, op)), - LLIL_ADC => ExprInfo::Adc(Operation::new(function, op)), - LLIL_SUB => ExprInfo::Sub(Operation::new(function, op)), - LLIL_SBB => ExprInfo::Sbb(Operation::new(function, op)), - LLIL_AND => ExprInfo::And(Operation::new(function, op)), - LLIL_OR => ExprInfo::Or(Operation::new(function, op)), - LLIL_XOR => ExprInfo::Xor(Operation::new(function, op)), - LLIL_LSL => ExprInfo::Lsl(Operation::new(function, op)), - LLIL_LSR => ExprInfo::Lsr(Operation::new(function, op)), - LLIL_ASR => ExprInfo::Asr(Operation::new(function, op)), - LLIL_ROL => ExprInfo::Rol(Operation::new(function, op)), - LLIL_RLC => ExprInfo::Rlc(Operation::new(function, op)), - LLIL_ROR => ExprInfo::Ror(Operation::new(function, op)), - LLIL_RRC => ExprInfo::Rrc(Operation::new(function, op)), - LLIL_MUL => ExprInfo::Mul(Operation::new(function, op)), - - LLIL_MULU_DP => ExprInfo::MuluDp(Operation::new(function, op)), - LLIL_MULS_DP => ExprInfo::MulsDp(Operation::new(function, op)), - - LLIL_DIVU => ExprInfo::Divu(Operation::new(function, op)), - LLIL_DIVS => ExprInfo::Divs(Operation::new(function, op)), - - LLIL_DIVU_DP => ExprInfo::DivuDp(Operation::new(function, op)), - LLIL_DIVS_DP => ExprInfo::DivsDp(Operation::new(function, op)), - - LLIL_MODU => ExprInfo::Modu(Operation::new(function, op)), - LLIL_MODS => ExprInfo::Mods(Operation::new(function, op)), - - LLIL_MODU_DP => ExprInfo::ModuDp(Operation::new(function, op)), - LLIL_MODS_DP => ExprInfo::ModsDp(Operation::new(function, op)), - - LLIL_NEG => ExprInfo::Neg(Operation::new(function, op)), - LLIL_NOT => ExprInfo::Not(Operation::new(function, op)), - - LLIL_SX => ExprInfo::Sx(Operation::new(function, op)), - LLIL_ZX => ExprInfo::Zx(Operation::new(function, op)), - LLIL_LOW_PART => ExprInfo::LowPart(Operation::new(function, op)), - - LLIL_REG_SPLIT => ExprInfo::RegSplit(Operation::new(function, op)), - - LLIL_CMP_E => ExprInfo::CmpE(Operation::new(function, op)), - LLIL_CMP_NE => ExprInfo::CmpNe(Operation::new(function, op)), - LLIL_CMP_SLT => ExprInfo::CmpSlt(Operation::new(function, op)), - LLIL_CMP_ULT => ExprInfo::CmpUlt(Operation::new(function, op)), - LLIL_CMP_SLE => ExprInfo::CmpSle(Operation::new(function, op)), - LLIL_CMP_ULE => ExprInfo::CmpUle(Operation::new(function, op)), - LLIL_CMP_SGE => ExprInfo::CmpSge(Operation::new(function, op)), - LLIL_CMP_UGE => ExprInfo::CmpUge(Operation::new(function, op)), - LLIL_CMP_SGT => ExprInfo::CmpSgt(Operation::new(function, op)), - LLIL_CMP_UGT => ExprInfo::CmpUgt(Operation::new(function, op)), - - LLIL_BOOL_TO_INT => ExprInfo::BoolToInt(Operation::new(function, op)), - - LLIL_FADD => ExprInfo::Fadd(Operation::new(function, op)), - LLIL_FSUB => ExprInfo::Fsub(Operation::new(function, op)), - LLIL_FMUL => ExprInfo::Fmul(Operation::new(function, op)), - LLIL_FDIV => ExprInfo::Fdiv(Operation::new(function, op)), - - LLIL_FSQRT => ExprInfo::Fsqrt(Operation::new(function, op)), - LLIL_FNEG => ExprInfo::Fneg(Operation::new(function, op)), - LLIL_FABS => ExprInfo::Fabs(Operation::new(function, op)), - LLIL_FLOAT_TO_INT => ExprInfo::FloatToInt(Operation::new(function, op)), - LLIL_INT_TO_FLOAT => ExprInfo::IntToFloat(Operation::new(function, op)), - LLIL_FLOAT_CONV => ExprInfo::FloatConv(Operation::new(function, op)), - LLIL_ROUND_TO_INT => ExprInfo::RoundToInt(Operation::new(function, op)), - LLIL_FLOOR => ExprInfo::Floor(Operation::new(function, op)), - LLIL_CEIL => ExprInfo::Ceil(Operation::new(function, op)), - LLIL_FTRUNC => ExprInfo::Ftrunc(Operation::new(function, op)), - - LLIL_FCMP_E => ExprInfo::FcmpE(Operation::new(function, op)), - LLIL_FCMP_NE => ExprInfo::FcmpNE(Operation::new(function, op)), - LLIL_FCMP_LT => ExprInfo::FcmpLT(Operation::new(function, op)), - LLIL_FCMP_LE => ExprInfo::FcmpLE(Operation::new(function, op)), - LLIL_FCMP_GT => ExprInfo::FcmpGT(Operation::new(function, op)), - LLIL_FCMP_GE => ExprInfo::FcmpGE(Operation::new(function, op)), - LLIL_FCMP_O => ExprInfo::FcmpO(Operation::new(function, op)), - LLIL_FCMP_UO => ExprInfo::FcmpUO(Operation::new(function, op)), - - LLIL_UNIMPL => ExprInfo::Unimpl(Operation::new(function, op)), - LLIL_UNIMPL_MEM => ExprInfo::UnimplMem(Operation::new(function, op)), - - // TODO TEST_BIT ADD_OVERFLOW LLIL_REG_STACK_PUSH LLIL_REG_STACK_POP - _ => { - #[cfg(debug_assertions)] - { - error!( - "Got unexpected operation {:?} in value expr at 0x{:x}", - op.operation, op.address - ); - } - - ExprInfo::Undef(Operation::new(function, op)) - } - } -} - -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: &ExprInfo<'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::ExprInfo::*; - - match *info { - CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) - | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) | CmpUgt(ref op) - | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) | FcmpGE(ref op) - | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => { - visit!(f, &op.left()); - visit!(f, &op.right()); - } - - Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => { - visit!(f, &op.left()); - visit!(f, &op.right()); - visit!(f, &op.carry()); - } - - Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) - | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) | MulsDp(ref op) - | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) | Mods(ref op) - | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => { - visit!(f, &op.left()); - visit!(f, &op.right()); - } - - DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => { - visit!(f, &op.high()); - visit!(f, &op.low()); - visit!(f, &op.right()); - } - - Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) - | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) | FloatToInt(ref op) - | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) | Floor(ref op) - | Ceil(ref op) | Ftrunc(ref op) => { - visit!(f, &op.operand()); - } - - UnimplMem(ref op) => { - visit!(f, &op.mem_expr()); - } - - _ => {} - }; - - VisitorAction::Sibling -} - -impl<'func, A, M, V> Expression<'func, A, M, NonSSA<V>, ValueExpr> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub(crate) unsafe fn info_from_op( - &self, - op: BNLowLevelILInstruction, - ) -> ExprInfo<'func, A, M, NonSSA<V>> { - use binaryninjacore_sys::BNLowLevelILOperation::*; - - match op.operation { - LLIL_LOAD => ExprInfo::Load(Operation::new(self.function, op)), - LLIL_POP => ExprInfo::Pop(Operation::new(self.function, op)), - LLIL_REG => ExprInfo::Reg(Operation::new(self.function, op)), - LLIL_REG_SPLIT => ExprInfo::RegSplit(Operation::new(self.function, op)), - LLIL_FLAG => ExprInfo::Flag(Operation::new(self.function, op)), - LLIL_FLAG_BIT => ExprInfo::FlagBit(Operation::new(self.function, op)), - LLIL_FLAG_COND => ExprInfo::FlagCond(Operation::new(self.function, op)), // TODO lifted only - LLIL_FLAG_GROUP => ExprInfo::FlagGroup(Operation::new(self.function, op)), // TODO lifted only - _ => common_info(self.function, op), - } - } - - pub fn info(&self) -> ExprInfo<'func, A, M, NonSSA<V>> { - unsafe { - let op = BNGetLowLevelILByIndex(self.function.handle, self.expr_idx); - self.info_from_op(op) - } - } - - pub fn visit_tree<F>(&self, f: &mut F) -> VisitorAction - where - F: FnMut(&Self, &ExprInfo<'func, A, M, NonSSA<V>>) -> VisitorAction, - { - use self::ExprInfo::*; - - let info = self.info(); - - match f(self, &info) { - VisitorAction::Descend => {} - action => return action, - }; - - match info { - Load(ref op) => visit!(Self::visit_tree, &op.source_mem_expr(), f), - _ => { - let mut fb = |e: &Self| e.visit_tree(f); - visit!(common_visit, &info, &mut fb); - } - }; - - VisitorAction::Sibling - } -} - -impl<'func, A, M> Expression<'func, A, M, SSA, ValueExpr> -where - A: 'func + Architecture, - M: FunctionMutability, -{ - pub(crate) unsafe fn info_from_op( - &self, - op: BNLowLevelILInstruction, - ) -> ExprInfo<'func, A, M, SSA> { - use binaryninjacore_sys::BNLowLevelILOperation::*; - - match op.operation { - LLIL_LOAD_SSA => ExprInfo::Load(Operation::new(self.function, op)), - LLIL_REG_SSA | LLIL_REG_SSA_PARTIAL => ExprInfo::Reg(Operation::new(self.function, op)), - LLIL_REG_SPLIT_SSA => ExprInfo::RegSplit(Operation::new(self.function, op)), - LLIL_FLAG_SSA => ExprInfo::Flag(Operation::new(self.function, op)), - LLIL_FLAG_BIT_SSA => ExprInfo::FlagBit(Operation::new(self.function, op)), - _ => common_info(self.function, op), - } - } - - pub fn info(&self) -> ExprInfo<'func, A, M, SSA> { - unsafe { - let op = BNGetLowLevelILByIndex(self.function.handle, self.expr_idx); - self.info_from_op(op) - } - } - - pub fn visit_tree<F>(&self, f: &mut F) -> VisitorAction - where - F: FnMut(&Self, &ExprInfo<'func, A, M, SSA>) -> VisitorAction, - { - use self::ExprInfo::*; - - let info = self.info(); - - match f(self, &info) { - VisitorAction::Descend => {} - action => return action, - }; - - match info { - // TODO ssa - Load(ref _op) => {} //visit!(Self::visit_tree, &op.source_mem_expr(), f), - _ => { - let mut fb = |e: &Self| e.visit_tree(f); - visit!(common_visit, &info, &mut fb); - } - }; - - VisitorAction::Sibling - } -} - -impl<'func, A, F> Expression<'func, A, Finalized, F, ValueExpr> -where - A: 'func + Architecture, - F: FunctionForm, -{ - // TODO possible values -} - -pub enum ExprInfo<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - Load(Operation<'func, A, M, F, operation::Load>), - Pop(Operation<'func, A, M, F, operation::Pop>), - Reg(Operation<'func, A, M, F, operation::Reg>), - RegSplit(Operation<'func, A, M, F, operation::RegSplit>), - Const(Operation<'func, A, M, F, operation::Const>), - ConstPtr(Operation<'func, A, M, F, operation::Const>), - Flag(Operation<'func, A, M, F, operation::Flag>), - FlagBit(Operation<'func, A, M, F, operation::FlagBit>), - ExternPtr(Operation<'func, A, M, F, operation::Extern>), - - Add(Operation<'func, A, M, F, operation::BinaryOp>), - Adc(Operation<'func, A, M, F, operation::BinaryOpCarry>), - Sub(Operation<'func, A, M, F, operation::BinaryOp>), - Sbb(Operation<'func, A, M, F, operation::BinaryOpCarry>), - And(Operation<'func, A, M, F, operation::BinaryOp>), - Or(Operation<'func, A, M, F, operation::BinaryOp>), - Xor(Operation<'func, A, M, F, operation::BinaryOp>), - Lsl(Operation<'func, A, M, F, operation::BinaryOp>), - Lsr(Operation<'func, A, M, F, operation::BinaryOp>), - Asr(Operation<'func, A, M, F, operation::BinaryOp>), - Rol(Operation<'func, A, M, F, operation::BinaryOp>), - Rlc(Operation<'func, A, M, F, operation::BinaryOpCarry>), - Ror(Operation<'func, A, M, F, operation::BinaryOp>), - Rrc(Operation<'func, A, M, F, operation::BinaryOpCarry>), - Mul(Operation<'func, A, M, F, operation::BinaryOp>), - - MulsDp(Operation<'func, A, M, F, operation::BinaryOp>), - MuluDp(Operation<'func, A, M, F, operation::BinaryOp>), - - Divu(Operation<'func, A, M, F, operation::BinaryOp>), - Divs(Operation<'func, A, M, F, operation::BinaryOp>), - - DivuDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - DivsDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - - Modu(Operation<'func, A, M, F, operation::BinaryOp>), - Mods(Operation<'func, A, M, F, operation::BinaryOp>), - - ModuDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - ModsDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - - Neg(Operation<'func, A, M, F, operation::UnaryOp>), - Not(Operation<'func, A, M, F, operation::UnaryOp>), - Sx(Operation<'func, A, M, F, operation::UnaryOp>), - Zx(Operation<'func, A, M, F, operation::UnaryOp>), - LowPart(Operation<'func, A, M, F, operation::UnaryOp>), - - FlagCond(Operation<'func, A, M, F, operation::FlagCond>), - FlagGroup(Operation<'func, A, M, F, operation::FlagGroup>), - - CmpE(Operation<'func, A, M, F, operation::Condition>), - CmpNe(Operation<'func, A, M, F, operation::Condition>), - CmpSlt(Operation<'func, A, M, F, operation::Condition>), - CmpUlt(Operation<'func, A, M, F, operation::Condition>), - CmpSle(Operation<'func, A, M, F, operation::Condition>), - CmpUle(Operation<'func, A, M, F, operation::Condition>), - CmpSge(Operation<'func, A, M, F, operation::Condition>), - CmpUge(Operation<'func, A, M, F, operation::Condition>), - CmpSgt(Operation<'func, A, M, F, operation::Condition>), - CmpUgt(Operation<'func, A, M, F, operation::Condition>), - - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO - BoolToInt(Operation<'func, A, M, F, operation::UnaryOp>), - - Fadd(Operation<'func, A, M, F, operation::BinaryOp>), - Fsub(Operation<'func, A, M, F, operation::BinaryOp>), - Fmul(Operation<'func, A, M, F, operation::BinaryOp>), - Fdiv(Operation<'func, A, M, F, operation::BinaryOp>), - Fsqrt(Operation<'func, A, M, F, operation::UnaryOp>), - Fneg(Operation<'func, A, M, F, operation::UnaryOp>), - Fabs(Operation<'func, A, M, F, operation::UnaryOp>), - FloatToInt(Operation<'func, A, M, F, operation::UnaryOp>), - IntToFloat(Operation<'func, A, M, F, operation::UnaryOp>), - FloatConv(Operation<'func, A, M, F, operation::UnaryOp>), - RoundToInt(Operation<'func, A, M, F, operation::UnaryOp>), - Floor(Operation<'func, A, M, F, operation::UnaryOp>), - Ceil(Operation<'func, A, M, F, operation::UnaryOp>), - Ftrunc(Operation<'func, A, M, F, operation::UnaryOp>), - - FcmpE(Operation<'func, A, M, F, operation::Condition>), - FcmpNE(Operation<'func, A, M, F, operation::Condition>), - FcmpLT(Operation<'func, A, M, F, operation::Condition>), - FcmpLE(Operation<'func, A, M, F, operation::Condition>), - FcmpGE(Operation<'func, A, M, F, operation::Condition>), - FcmpGT(Operation<'func, A, M, F, operation::Condition>), - FcmpO(Operation<'func, A, M, F, operation::Condition>), - FcmpUO(Operation<'func, A, M, F, operation::Condition>), - - // TODO ADD_OVERFLOW - Unimpl(Operation<'func, A, M, F, operation::NoArgs>), - UnimplMem(Operation<'func, A, M, F, operation::UnimplMem>), - - Undef(Operation<'func, A, M, F, operation::NoArgs>), -} - -impl<'func, A, M, F> ExprInfo<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - /// Returns the size of the result of this expression - /// - /// If the expression is malformed or is `Unimpl` there - /// is no meaningful size associated with the result. - pub fn size(&self) -> Option<usize> { - use self::ExprInfo::*; - - match *self { - Undef(..) | Unimpl(..) => None, - - FlagCond(..) | FlagGroup(..) | CmpE(..) | CmpNe(..) | CmpSlt(..) | CmpUlt(..) - | CmpSle(..) | CmpUle(..) | CmpSge(..) | CmpUge(..) | CmpSgt(..) | CmpUgt(..) => { - Some(0) - } - - _ => Some(self.raw_struct().size), - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO - } - } - - pub fn address(&self) -> u64 { - self.raw_struct().address - } - - /// Determines if the expressions represent the same operation - /// - /// It does not examine the operands for equality. - pub fn is_same_op_as(&self, other: &Self) -> bool { - use self::ExprInfo::*; - - match (self, other) { - (&Reg(..), &Reg(..)) => true, - _ => self.raw_struct().operation == other.raw_struct().operation, - } - } - - pub fn as_cmp_op(&self) -> Option<&Operation<'func, A, M, F, operation::Condition>> { - use self::ExprInfo::*; - - match *self { - CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) - | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) - | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) - | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => Some(op), - _ => None, - } - } - - pub fn as_binary_op(&self) -> Option<&Operation<'func, A, M, F, operation::BinaryOp>> { - use self::ExprInfo::*; - - match *self { - Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) - | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) - | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) - | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => Some(op), - _ => None, - } - } - - pub fn as_binary_op_carry( - &self, - ) -> Option<&Operation<'func, A, M, F, operation::BinaryOpCarry>> { - use self::ExprInfo::*; - - match *self { - Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => Some(op), - _ => None, - } - } - - pub fn as_double_prec_div_op( - &self, - ) -> Option<&Operation<'func, A, M, F, operation::DoublePrecDivOp>> { - use self::ExprInfo::*; - - match *self { - DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => Some(op), - _ => None, - } - } - - pub fn as_unary_op(&self) -> Option<&Operation<'func, A, M, F, operation::UnaryOp>> { - use self::ExprInfo::*; - - match *self { - Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) - | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) - | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) - | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => Some(op), - _ => None, - } - } - - pub(crate) fn raw_struct(&self) -> &BNLowLevelILInstruction { - use self::ExprInfo::*; - - match *self { - Undef(ref op) => &op.op, - - Unimpl(ref op) => &op.op, - - FlagCond(ref op) => &op.op, - FlagGroup(ref op) => &op.op, - - CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) - | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) - | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) - | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => &op.op, - - Load(ref op) => &op.op, - - Pop(ref op) => &op.op, - - Reg(ref op) => &op.op, - - RegSplit(ref op) => &op.op, - - Flag(ref op) => &op.op, - - FlagBit(ref op) => &op.op, - - Const(ref op) | ConstPtr(ref op) => &op.op, - - ExternPtr(ref op) => &op.op, - - Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op, - - Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) - | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) - | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) - | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => &op.op, - - DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => &op.op, - - Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) - | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) - | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) - | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op, - - UnimplMem(ref op) => &op.op, - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO - } - } -} - -impl<'func, A> ExprInfo<'func, A, Mutable, NonSSA<LiftedNonSSA>> -where - A: 'func + Architecture, -{ - pub fn flag_write(&self) -> Option<A::FlagWrite> { - use self::ExprInfo::*; - - match *self { - Undef(ref _op) => None, - - Unimpl(ref _op) => None, - - FlagCond(ref _op) => None, - FlagGroup(ref _op) => None, - - CmpE(ref _op) | CmpNe(ref _op) | CmpSlt(ref _op) | CmpUlt(ref _op) - | CmpSle(ref _op) | CmpUle(ref _op) | CmpSge(ref _op) | CmpUge(ref _op) - | CmpSgt(ref _op) | CmpUgt(ref _op) | FcmpE(ref _op) | FcmpNE(ref _op) - | FcmpLT(ref _op) | FcmpLE(ref _op) | FcmpGE(ref _op) | FcmpGT(ref _op) - | FcmpO(ref _op) | FcmpUO(ref _op) => None, - - Load(ref op) => op.flag_write(), - - Pop(ref op) => op.flag_write(), - - Reg(ref op) => op.flag_write(), - - RegSplit(ref op) => op.flag_write(), - - Flag(ref op) => op.flag_write(), - - FlagBit(ref op) => op.flag_write(), - - Const(ref op) | ConstPtr(ref op) => op.flag_write(), - - ExternPtr(ref op) => op.flag_write(), - - Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(), - - Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) - | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) - | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) - | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => { - op.flag_write() - } - - DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => op.flag_write(), - - Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) - | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) - | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) - | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(), - - UnimplMem(ref op) => op.flag_write(), - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO - } - } -} - -impl<'func, A, M, V> fmt::Debug for ExprInfo<'func, A, M, NonSSA<V>> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::ExprInfo::*; - - match *self { - Undef(..) => f.write_str("undefined"), - - Unimpl(..) => f.write_str("unimplemented"), - - FlagCond(..) => f.write_str("some_flag_cond"), - FlagGroup(..) => f.write_str("some_flag_group"), - - CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) - | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) - | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) - | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => { - let left = op.left(); - let right = op.right(); - - write!( - f, - "{:?}({}, {:?}, {:?})", - op.op.operation, - op.size(), - left, - right - ) - } - - Load(ref op) => { - let source = op.source_mem_expr(); - let size = op.size(); - - write!(f, "[{:?}].{}", source, size) - } - - Pop(ref op) => write!(f, "pop.{}", op.size()), - - Reg(ref op) => { - let reg = op.source_reg(); - let size = op.size(); - - let size = match reg { - Register::Temp(_) => Some(size), - Register::ArchReg(ref r) if r.info().size() != size => Some(size), - _ => None, - }; - - match size { - Some(s) => write!(f, "{:?}.{}", reg, s), - _ => write!(f, "{:?}", reg), - } - } - - RegSplit(ref op) => { - let low_reg = op.low_reg(); - let high_reg = op.high_reg(); - let size = op.size(); - - let low_size = match low_reg { - Register::Temp(_) => Some(size), - Register::ArchReg(ref r) if r.info().size() != size => Some(size), - _ => None, - }; - - let high_size = match high_reg { - Register::Temp(_) => Some(size), - Register::ArchReg(ref r) if r.info().size() != size => Some(size), - _ => None, - }; - - match (low_size, high_size) { - (Some(ls), Some(hs)) => write!(f, "{:?}.{}:{:?}.{}", high_reg, hs, low_reg, ls), - (Some(ls), None) => write!(f, "{:?}:{:?}.{}", high_reg, low_reg, ls), - (None, Some(hs)) => write!(f, "{:?}.{}:{:?}", high_reg, hs, low_reg), - _ => write!(f, "{:?}:{:?}", high_reg, low_reg), - } - } - - Flag(ref _op) => write!(f, "flag"), // TODO - - FlagBit(ref _op) => write!(f, "flag_bit"), // TODO - - Const(ref op) | ConstPtr(ref op) => write!(f, "0x{:x}", op.value()), - - ExternPtr(ref op) => write!(f, "0x{:x}", op.value()), - - Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => { - let left = op.left(); - let right = op.right(); - let carry = op.carry(); - - write!( - f, - "{:?}({}, {:?}, {:?}, carry: {:?})", - op.op.operation, - op.size(), - left, - right, - carry - ) - } - - Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) - | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) - | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) - | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => { - let left = op.left(); - let right = op.right(); - - write!( - f, - "{:?}({}, {:?}, {:?})", - op.op.operation, - op.size(), - left, - right - ) - } - - DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => { - let high = op.high(); - let low = op.low(); - let right = op.right(); - - write!( - f, - "{:?}({}, {:?}:{:?},{:?})", - op.op.operation, - op.size(), - high, - low, - right - ) - } - - Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) - | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) - | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) - | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => write!( - f, - "{:?}({}, {:?})", - op.op.operation, - op.size(), - op.operand() - ), - - UnimplMem(ref op) => write!(f, "unimplemented_mem({:?})", op.mem_expr()), - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO - } - } -} diff --git a/rust/src/llil/function.rs b/rust/src/llil/function.rs deleted file mode 100644 index abc501e5..00000000 --- a/rust/src/llil/function.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use binaryninjacore_sys::BNFreeLowLevelILFunction; -use binaryninjacore_sys::BNGetLowLevelILOwnerFunction; -use binaryninjacore_sys::BNLowLevelILFunction; -use binaryninjacore_sys::BNNewLowLevelILFunctionReference; - -use std::borrow::Borrow; -use std::marker::PhantomData; - -use crate::architecture::CoreArchitecture; -use crate::basicblock::BasicBlock; -use crate::rc::*; - -use super::*; - -#[derive(Copy, Clone, Debug)] -pub struct Mutable; -#[derive(Copy, Clone, Debug)] -pub struct Finalized; - -pub trait FunctionMutability: 'static {} -impl FunctionMutability for Mutable {} -impl FunctionMutability for Finalized {} - -#[derive(Copy, Clone, Debug)] -pub struct LiftedNonSSA; -#[derive(Copy, Clone, Debug)] -pub struct RegularNonSSA; - -pub trait NonSSAVariant: 'static {} -impl NonSSAVariant for LiftedNonSSA {} -impl NonSSAVariant for RegularNonSSA {} - -#[derive(Copy, Clone, Debug)] -pub struct SSA; -#[derive(Copy, Clone, Debug)] -pub struct NonSSA<V: NonSSAVariant>(V); - -pub trait FunctionForm: 'static {} -impl FunctionForm for SSA {} -impl<V: NonSSAVariant> FunctionForm for NonSSA<V> {} - -pub struct Function<A: Architecture, M: FunctionMutability, F: FunctionForm> { - pub(crate) borrower: A::Handle, - pub(crate) handle: *mut BNLowLevelILFunction, - _arch: PhantomData<*mut A>, - _mutability: PhantomData<M>, - _form: PhantomData<F>, -} - -unsafe impl<A: Architecture, M: FunctionMutability, F: FunctionForm> Send for Function<A, M, F> {} -unsafe impl<A: Architecture, M: FunctionMutability, F: FunctionForm> Sync for Function<A, M, F> {} - -impl<A: Architecture, M: FunctionMutability, F: FunctionForm> Eq for Function<A, M, F> {} -impl<A: Architecture, M: FunctionMutability, F: FunctionForm> PartialEq for Function<A, M, F> { - fn eq(&self, rhs: &Self) -> bool { - self.get_function().eq(&rhs.get_function()) - } -} - -use std::hash::{Hash, Hasher}; -impl<A: Architecture, M: FunctionMutability, F: FunctionForm> Hash for Function<A, M, F> { - fn hash<H: Hasher>(&self, state: &mut H) { - self.get_function().hash(state) - } -} - -impl<'func, A, M, F> Function<A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub(crate) unsafe fn from_raw(borrower: A::Handle, handle: *mut BNLowLevelILFunction) -> Self { - debug_assert!(!handle.is_null()); - - Self { - borrower, - handle, - _arch: PhantomData, - _mutability: PhantomData, - _form: PhantomData, - } - } - - pub(crate) unsafe fn ref_from_raw( - borrower: A::Handle, - handle: *mut BNLowLevelILFunction, - ) -> Ref<Self> { - Ref::new(Self::from_raw(borrower, handle)) - } - - pub(crate) fn arch(&self) -> &A { - self.borrower.borrow() - } - - pub fn instruction_at<L: Into<Location>>(&self, loc: L) -> Option<Instruction<A, M, F>> { - use binaryninjacore_sys::BNGetLowLevelILInstructionCount; - use binaryninjacore_sys::BNLowLevelILGetInstructionStart; - - let loc: Location = loc.into(); - let arch_handle = loc.arch.unwrap_or_else(|| *self.arch().as_ref()); - - unsafe { - let instr_idx = BNLowLevelILGetInstructionStart(self.handle, arch_handle.0, loc.addr); - - if instr_idx >= BNGetLowLevelILInstructionCount(self.handle) { - None - } else { - Some(Instruction { - function: self, - instr_idx, - }) - } - } - } - - pub fn instruction_from_idx(&self, instr_idx: usize) -> Instruction<A, M, F> { - unsafe { - use binaryninjacore_sys::BNGetLowLevelILInstructionCount; - if instr_idx >= BNGetLowLevelILInstructionCount(self.handle) { - panic!("instruction index {} out of bounds", instr_idx); - } - - Instruction { - function: self, - instr_idx, - } - } - } - - pub fn instruction_count(&self) -> usize { - unsafe { - use binaryninjacore_sys::BNGetLowLevelILInstructionCount; - BNGetLowLevelILInstructionCount(self.handle) - } - } - - pub fn get_function(&self) -> Ref<crate::function::Function> { - unsafe { - let func = BNGetLowLevelILOwnerFunction(self.handle); - crate::function::Function::from_raw(func) - } - } -} - -// LLIL basic blocks are not available until the function object -// is finalized, so ensure we can't try requesting basic blocks -// during lifting -impl<'func, A, F> Function<A, Finalized, F> -where - A: 'func + Architecture, - F: FunctionForm, -{ - pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelBlock<A, Finalized, F>>> { - use binaryninjacore_sys::BNGetLowLevelILBasicBlockList; - - unsafe { - let mut count = 0; - let blocks = BNGetLowLevelILBasicBlockList(self.handle, &mut count); - let context = LowLevelBlock { function: self }; - - Array::new(blocks, count, context) - } - } -} - -// Allow instantiating Lifted IL functions for querying Lifted IL from Architectures -impl Function<CoreArchitecture, Mutable, NonSSA<LiftedNonSSA>> { - pub fn new( - arch: CoreArchitecture, - source_func: Option<crate::function::Function>, - ) -> Result<Ref<Self>, ()> { - use binaryninjacore_sys::BNCreateLowLevelILFunction; - use std::ptr::null_mut; - - let handle = unsafe { - match source_func { - Some(func) => BNCreateLowLevelILFunction(arch.0, func.handle), - None => BNCreateLowLevelILFunction(arch.0, null_mut()), - } - }; - if handle.is_null() { - return Err(()); - } - - Ok(unsafe { - Ref::new(Self { - borrower: arch, - handle, - _arch: PhantomData, - _mutability: PhantomData, - _form: PhantomData, - }) - }) - } -} - -impl<'func, A, M, F> ToOwned for Function<A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - type Owned = Ref<Self>; - - fn to_owned(&self) -> Self::Owned { - unsafe { RefCountable::inc_ref(self) } - } -} - -unsafe impl<'func, A, M, F> RefCountable for Function<A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - unsafe fn inc_ref(handle: &Self) -> Ref<Self> { - Ref::new(Self { - borrower: handle.borrower.clone(), - handle: BNNewLowLevelILFunctionReference(handle.handle), - _arch: PhantomData, - _mutability: PhantomData, - _form: PhantomData, - }) - } - - unsafe fn dec_ref(handle: &Self) { - BNFreeLowLevelILFunction(handle.handle); - } -} - -impl<'func, A, M, F> fmt::Debug for Function<A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "<llil func handle {:p}>", self.handle) - } -} diff --git a/rust/src/llil/instruction.rs b/rust/src/llil/instruction.rs deleted file mode 100644 index 62e50453..00000000 --- a/rust/src/llil/instruction.rs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use binaryninjacore_sys::BNGetLowLevelILByIndex; -use binaryninjacore_sys::BNGetLowLevelILIndexForInstruction; -use binaryninjacore_sys::BNLowLevelILInstruction; - -use super::operation; -use super::operation::Operation; -use super::*; - -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 address(&self) -> u64 { - let expr_idx = - unsafe { BNGetLowLevelILIndexForInstruction(self.function.handle, self.instr_idx) }; - let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, expr_idx) }; - op.address - } - - 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_TAILCALL => InstrInfo::TailCall(Operation::new(self.function, op)), - LLIL_SYSCALL => InstrInfo::Syscall(Operation::new(self.function, op)), - LLIL_INTRINSIC => InstrInfo::Intrinsic(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::new(self.function, expr_idx); - - 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) | TailCall(ref op) => visit!(fb, &op.target()), - Intrinsic(ref _op) => { - // TODO: Use this when we support expression lists - // for expr in op.source_exprs() { - // visit!(fb, expr); - // } - } - _ => 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>), - TailCall(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>), - Intrinsic(Operation<'func, A, M, F, operation::Intrinsic>), - 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>, - ), -} diff --git a/rust/src/llil/lifting.rs b/rust/src/llil/lifting.rs deleted file mode 100644 index 840e029b..00000000 --- a/rust/src/llil/lifting.rs +++ /dev/null @@ -1,1492 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::marker::PhantomData; -use std::mem; - -use crate::architecture::Architecture; -use crate::architecture::Register as ArchReg; -use crate::architecture::{ - Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic, -}; - -use super::*; - -pub trait Liftable<'func, A: 'func + Architecture> { - type Result: ExpressionResultType; - - fn lift( - il: &'func Function<A, Mutable, NonSSA<LiftedNonSSA>>, - expr: Self, - ) -> Expression<'func, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result>; -} - -pub trait LiftableWithSize<'func, A: 'func + Architecture>: - Liftable<'func, A, Result = ValueExpr> -{ - fn lift_with_size( - il: &'func Function<A, Mutable, NonSSA<LiftedNonSSA>>, - expr: Self, - size: usize, - ) -> Expression<'func, A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr>; -} - -use binaryninjacore_sys::BNRegisterOrConstant; - -#[derive(Copy, Clone)] -pub enum RegisterOrConstant<R: ArchReg> { - Register(usize, Register<R>), - Constant(usize, u64), -} - -impl<R: ArchReg> RegisterOrConstant<R> { - pub(crate) fn into_api(self) -> BNRegisterOrConstant { - match self { - RegisterOrConstant::Register(_, r) => BNRegisterOrConstant { - constant: false, - reg: r.id(), - value: 0, - }, - RegisterOrConstant::Constant(_, value) => BNRegisterOrConstant { - constant: true, - reg: 0, - value, - }, - } - } -} - -// TODO flesh way out -#[derive(Copy, Clone)] -pub enum FlagWriteOp<R: ArchReg> { - SetReg(usize, RegisterOrConstant<R>), - SetRegSplit(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - - Sub(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Add(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - - Load(usize, RegisterOrConstant<R>), - - Push(usize, RegisterOrConstant<R>), - Neg(usize, RegisterOrConstant<R>), - Not(usize, RegisterOrConstant<R>), - Sx(usize, RegisterOrConstant<R>), - Zx(usize, RegisterOrConstant<R>), - LowPart(usize, RegisterOrConstant<R>), - BoolToInt(usize, RegisterOrConstant<R>), - FloatToInt(usize, RegisterOrConstant<R>), - - Store(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - - And(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Or(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Xor(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Lsl(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Lsr(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Asr(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Rol(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Ror(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Mul(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - MuluDp(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - MulsDp(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Divu(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Divs(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Modu(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - Mods(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - DivuDp(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - DivsDp(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - ModuDp(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - ModsDp(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - - TestBit(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - AddOverflow(usize, RegisterOrConstant<R>, RegisterOrConstant<R>), - - Adc( - usize, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - ), - Sbb( - usize, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - ), - Rlc( - usize, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - ), - Rrc( - usize, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - RegisterOrConstant<R>, - ), - - Pop(usize), - // TODO: floating point stuff, llil comparison ops that set flags, intrinsics -} - -impl<R: ArchReg> FlagWriteOp<R> { - pub(crate) fn from_op<A>( - arch: &A, - size: usize, - op: BNLowLevelILOperation, - operands: &[BNRegisterOrConstant], - ) -> Option<Self> - where - A: Architecture<Register = R>, - R: ArchReg<InfoType = A::RegisterInfo>, - { - use self::FlagWriteOp::*; - use binaryninjacore_sys::BNLowLevelILOperation::*; - - fn build_op<A, R>( - arch: &A, - size: usize, - operand: &BNRegisterOrConstant, - ) -> RegisterOrConstant<R> - where - A: Architecture<Register = R>, - R: ArchReg<InfoType = A::RegisterInfo>, - { - if operand.constant { - RegisterOrConstant::Constant(size, operand.value) - } else { - let il_reg = if 0x8000_0000 & operand.reg == 0 { - Register::ArchReg(arch.register_from_id(operand.reg).unwrap()) - } else { - Register::Temp(operand.reg) - }; - - RegisterOrConstant::Register(size, il_reg) - } - } - - macro_rules! op { - ($x:ident, $($ops:expr),*) => { - ( $x(size, $( build_op(arch, size, &operands[$ops]), )* ) ) - }; - } - - Some(match (operands.len(), op) { - (1, LLIL_SET_REG) => op!(SetReg, 0), - (2, LLIL_SET_REG_SPLIT) => op!(SetRegSplit, 0, 1), - - (2, LLIL_SUB) => op!(Sub, 0, 1), - (2, LLIL_ADD) => op!(Add, 0, 1), - - (1, LLIL_LOAD) => op!(Load, 0), - - (1, LLIL_PUSH) => op!(Push, 0), - (1, LLIL_NEG) => op!(Neg, 0), - (1, LLIL_NOT) => op!(Not, 0), - (1, LLIL_SX) => op!(Sx, 0), - (1, LLIL_ZX) => op!(Zx, 0), - (1, LLIL_LOW_PART) => op!(LowPart, 0), - (1, LLIL_BOOL_TO_INT) => op!(BoolToInt, 0), - (1, LLIL_FLOAT_TO_INT) => op!(FloatToInt, 0), - - (2, LLIL_STORE) => op!(Store, 0, 1), - - (2, LLIL_AND) => op!(And, 0, 1), - (2, LLIL_OR) => op!(Or, 0, 1), - (2, LLIL_XOR) => op!(Xor, 0, 1), - (2, LLIL_LSL) => op!(Lsl, 0, 1), - (2, LLIL_LSR) => op!(Lsr, 0, 1), - (2, LLIL_ASR) => op!(Asr, 0, 1), - (2, LLIL_ROL) => op!(Rol, 0, 1), - (2, LLIL_ROR) => op!(Ror, 0, 1), - (2, LLIL_MUL) => op!(Mul, 0, 1), - (2, LLIL_MULU_DP) => op!(MuluDp, 0, 1), - (2, LLIL_MULS_DP) => op!(MulsDp, 0, 1), - (2, LLIL_DIVU) => op!(Divu, 0, 1), - (2, LLIL_DIVS) => op!(Divs, 0, 1), - (2, LLIL_MODU) => op!(Modu, 0, 1), - (2, LLIL_MODS) => op!(Mods, 0, 1), - (2, LLIL_DIVU_DP) => op!(DivuDp, 0, 1), - (2, LLIL_DIVS_DP) => op!(DivsDp, 0, 1), - (2, LLIL_MODU_DP) => op!(ModuDp, 0, 1), - (2, LLIL_MODS_DP) => op!(ModsDp, 0, 1), - - (2, LLIL_TEST_BIT) => op!(TestBit, 0, 1), - (2, LLIL_ADD_OVERFLOW) => op!(AddOverflow, 0, 1), - - (3, LLIL_ADC) => op!(Adc, 0, 1, 2), - (3, LLIL_SBB) => op!(Sbb, 0, 1, 2), - (3, LLIL_RLC) => op!(Rlc, 0, 1, 2), - (3, LLIL_RRC) => op!(Rrc, 0, 1, 2), - - (0, LLIL_POP) => op!(Pop,), - - _ => return None, - }) - } - - pub(crate) fn size_and_op(&self) -> (usize, BNLowLevelILOperation) { - use self::FlagWriteOp::*; - use binaryninjacore_sys::BNLowLevelILOperation::*; - - match *self { - SetReg(size, ..) => (size, LLIL_SET_REG), - SetRegSplit(size, ..) => (size, LLIL_SET_REG_SPLIT), - - Sub(size, ..) => (size, LLIL_SUB), - Add(size, ..) => (size, LLIL_ADD), - - Load(size, ..) => (size, LLIL_LOAD), - - Push(size, ..) => (size, LLIL_PUSH), - Neg(size, ..) => (size, LLIL_NEG), - Not(size, ..) => (size, LLIL_NOT), - Sx(size, ..) => (size, LLIL_SX), - Zx(size, ..) => (size, LLIL_ZX), - LowPart(size, ..) => (size, LLIL_LOW_PART), - BoolToInt(size, ..) => (size, LLIL_BOOL_TO_INT), - FloatToInt(size, ..) => (size, LLIL_FLOAT_TO_INT), - - Store(size, ..) => (size, LLIL_STORE), - - And(size, ..) => (size, LLIL_AND), - Or(size, ..) => (size, LLIL_OR), - Xor(size, ..) => (size, LLIL_XOR), - Lsl(size, ..) => (size, LLIL_LSL), - Lsr(size, ..) => (size, LLIL_LSR), - Asr(size, ..) => (size, LLIL_ASR), - Rol(size, ..) => (size, LLIL_ROL), - Ror(size, ..) => (size, LLIL_ROR), - Mul(size, ..) => (size, LLIL_MUL), - MuluDp(size, ..) => (size, LLIL_MULU_DP), - MulsDp(size, ..) => (size, LLIL_MULS_DP), - Divu(size, ..) => (size, LLIL_DIVU), - Divs(size, ..) => (size, LLIL_DIVS), - Modu(size, ..) => (size, LLIL_MODU), - Mods(size, ..) => (size, LLIL_MODS), - DivuDp(size, ..) => (size, LLIL_DIVU_DP), - DivsDp(size, ..) => (size, LLIL_DIVS_DP), - ModuDp(size, ..) => (size, LLIL_MODU_DP), - ModsDp(size, ..) => (size, LLIL_MODS_DP), - - TestBit(size, ..) => (size, LLIL_TEST_BIT), - AddOverflow(size, ..) => (size, LLIL_ADD_OVERFLOW), - - Adc(size, ..) => (size, LLIL_ADC), - Sbb(size, ..) => (size, LLIL_SBB), - Rlc(size, ..) => (size, LLIL_RLC), - Rrc(size, ..) => (size, LLIL_RRC), - - Pop(size) => (size, LLIL_POP), - } - } - - pub(crate) fn api_operands(&self) -> (usize, [BNRegisterOrConstant; 5]) { - use self::FlagWriteOp::*; - - let mut operands: [BNRegisterOrConstant; 5] = unsafe { mem::zeroed() }; - - let count = match *self { - Pop(_) => 0, - - SetReg(_, op0) - | Load(_, op0) - | Push(_, op0) - | Neg(_, op0) - | Not(_, op0) - | Sx(_, op0) - | Zx(_, op0) - | LowPart(_, op0) - | BoolToInt(_, op0) - | FloatToInt(_, op0) => { - operands[0] = op0.into_api(); - 1 - } - - SetRegSplit(_, op0, op1) - | Sub(_, op0, op1) - | Add(_, op0, op1) - | Store(_, op0, op1) - | And(_, op0, op1) - | Or(_, op0, op1) - | Xor(_, op0, op1) - | Lsl(_, op0, op1) - | Lsr(_, op0, op1) - | Asr(_, op0, op1) - | Rol(_, op0, op1) - | Ror(_, op0, op1) - | Mul(_, op0, op1) - | MuluDp(_, op0, op1) - | MulsDp(_, op0, op1) - | Divu(_, op0, op1) - | Divs(_, op0, op1) - | Modu(_, op0, op1) - | Mods(_, op0, op1) - | DivuDp(_, op0, op1) - | DivsDp(_, op0, op1) - | ModuDp(_, op0, op1) - | ModsDp(_, op0, op1) - | TestBit(_, op0, op1) - | AddOverflow(_, op0, op1) => { - operands[0] = op0.into_api(); - operands[1] = op1.into_api(); - 2 - } - - Adc(_, op0, op1, op2) - | Sbb(_, op0, op1, op2) - | Rlc(_, op0, op1, op2) - | Rrc(_, op0, op1, op2) => { - operands[0] = op0.into_api(); - operands[1] = op1.into_api(); - operands[2] = op2.into_api(); - 3 - } - }; - - (count, operands) - } -} - -pub fn get_default_flag_write_llil<'func, A>( - arch: &A, - role: FlagRole, - op: FlagWriteOp<A::Register>, - il: &'func Lifter<A>, -) -> LiftedExpr<'func, A> -where - A: 'func + Architecture, -{ - let (size, operation) = op.size_and_op(); - let (count, operands) = op.api_operands(); - - let expr_idx = unsafe { - use binaryninjacore_sys::BNGetDefaultArchitectureFlagWriteLowLevelIL; - BNGetDefaultArchitectureFlagWriteLowLevelIL( - arch.as_ref().0, - operation, - size, - role, - operands.as_ptr() as *mut _, - count, - il.handle, - ) - }; - - Expression::new(il, expr_idx) -} - -pub fn get_default_flag_cond_llil<'func, A>( - arch: &A, - cond: FlagCondition, - class: Option<A::FlagClass>, - il: &'func Lifter<A>, -) -> LiftedExpr<'func, A> -where - A: 'func + Architecture, -{ - use binaryninjacore_sys::BNGetDefaultArchitectureFlagConditionLowLevelIL; - - let handle = arch.as_ref(); - let class_id = class.map(|c| c.id()).unwrap_or(0); - - unsafe { - let expr_idx = - BNGetDefaultArchitectureFlagConditionLowLevelIL(handle.0, cond, class_id, il.handle); - - Expression::new(il, expr_idx) - } -} - -macro_rules! prim_int_lifter { - ($x:ty) => { - impl<'a, A: 'a + Architecture> Liftable<'a, A> for $x { - type Result = ValueExpr; - - fn lift(il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, val: Self) - -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> - { - il.const_int(mem::size_of::<Self>(), val as i64 as u64) - } - } - - impl<'a, A: 'a + Architecture> LiftableWithSize<'a, A> for $x { - fn lift_with_size(il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, val: Self, size: usize) - -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { - let raw = val as i64; - - #[cfg(debug_assertions)] - { - let is_safe = match raw.overflowing_shr(size as u32 * 8) { - (_, true) => true, - (res, false) => [-1, 0].contains(&res), - }; - - if !is_safe { - error!("il @ {:x} attempted to lift constant 0x{:x} as {} byte expr (won't fit!)", - il.current_address(), val, size); - } - } - - il.const_int(size, raw as u64) - } - } - } -} - -prim_int_lifter!(i8); -prim_int_lifter!(i16); -prim_int_lifter!(i32); -prim_int_lifter!(i64); - -prim_int_lifter!(u8); -prim_int_lifter!(u16); -prim_int_lifter!(u32); -prim_int_lifter!(u64); - -impl<'a, R: ArchReg, A: 'a + Architecture> Liftable<'a, A> for Register<R> -where - R: Liftable<'a, A, Result = ValueExpr> + Into<Register<R>>, -{ - type Result = ValueExpr; - - fn lift( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - reg: Self, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> { - match reg { - Register::ArchReg(r) => R::lift(il, r), - Register::Temp(t) => il.reg(il.arch().default_integer_size(), Register::Temp(t)), - } - } -} - -impl<'a, R: ArchReg, A: 'a + Architecture> LiftableWithSize<'a, A> for Register<R> -where - R: LiftableWithSize<'a, A> + Into<Register<R>>, -{ - fn lift_with_size( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - reg: Self, - size: usize, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - match reg { - Register::ArchReg(r) => R::lift_with_size(il, r, size), - Register::Temp(t) => il.reg(size, Register::Temp(t)), - } - } -} - -impl<'a, R: ArchReg, A: 'a + Architecture> Liftable<'a, A> for RegisterOrConstant<R> -where - R: LiftableWithSize<'a, A, Result = ValueExpr> + Into<Register<R>>, -{ - type Result = ValueExpr; - - fn lift( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - reg: Self, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> { - match reg { - RegisterOrConstant::Register(size, r) => Register::<R>::lift_with_size(il, r, size), - RegisterOrConstant::Constant(size, value) => u64::lift_with_size(il, value, size), - } - } -} - -impl<'a, R: ArchReg, A: 'a + Architecture> LiftableWithSize<'a, A> for RegisterOrConstant<R> -where - R: LiftableWithSize<'a, A> + Into<Register<R>>, -{ - fn lift_with_size( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - reg: Self, - size: usize, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - // TODO ensure requested size is compatible with size of this constant - match reg { - RegisterOrConstant::Register(_, r) => Register::<R>::lift_with_size(il, r, size), - RegisterOrConstant::Constant(_, value) => u64::lift_with_size(il, value, size), - } - } -} - -impl<'a, A, R> Liftable<'a, A> for Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R> -where - A: 'a + Architecture, - R: ExpressionResultType, -{ - type Result = R; - - fn lift( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - expr: Self, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> { - debug_assert!(expr.function.handle == il.handle); - expr - } -} - -impl<'a, A: 'a + Architecture> LiftableWithSize<'a, A> - for Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> -{ - fn lift_with_size( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - expr: Self, - _size: usize, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> { - #[cfg(debug_assertions)] - { - if let Some(expr_size) = expr.info().size() { - if expr_size != _size { - warn!( - "il @ {:x} attempted to lift {} byte expression as {} bytes", - il.current_address(), - expr_size, - _size - ); - } - } - } - - Liftable::lift(il, expr) - } -} - -impl<'func, A, R> Expression<'func, A, Mutable, NonSSA<LiftedNonSSA>, R> -where - A: 'func + Architecture, - R: ExpressionResultType, -{ - pub fn with_source_operand(self, op: u32) -> Self { - use binaryninjacore_sys::BNLowLevelILSetExprSourceOperand; - - unsafe { BNLowLevelILSetExprSourceOperand(self.function.handle, self.expr_idx, op) } - - self - } - - pub fn append(self) { - let il = self.function; - il.instruction(self); - } -} - -use binaryninjacore_sys::BNLowLevelILOperation; -pub struct ExpressionBuilder<'func, A, R> -where - A: 'func + Architecture, - R: ExpressionResultType, -{ - function: &'func Function<A, Mutable, NonSSA<LiftedNonSSA>>, - op: BNLowLevelILOperation, - size: usize, - flags: u32, - op1: u64, - op2: u64, - op3: u64, - op4: u64, - _ty: PhantomData<R>, -} - -impl<'a, A, R> ExpressionBuilder<'a, A, R> -where - A: 'a + Architecture, - R: ExpressionResultType, -{ - pub fn from_expr(expr: Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R>) -> Self { - use binaryninjacore_sys::BNGetLowLevelILByIndex; - - let instr = unsafe { - BNGetLowLevelILByIndex(expr.function.handle, expr.expr_idx) - }; - - ExpressionBuilder { - function: expr.function, - op: instr.operation, - size: instr.size, - flags: instr.flags, - op1: instr.operands[0], - op2: instr.operands[1], - op3: instr.operands[2], - op4: instr.operands[3], - _ty: PhantomData - } - } - - pub fn with_flag_write(mut self, flag_write: A::FlagWrite) -> Self { - // TODO verify valid id - self.flags = flag_write.id(); - self - } - - pub fn build(self) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - - let expr_idx = unsafe { - BNLowLevelILAddExpr( - self.function.handle, - self.op, - self.size, - self.flags, - self.op1, - self.op2, - self.op3, - self.op4, - ) - }; - - Expression::new(self.function, expr_idx) - } - - pub fn with_source_operand( - self, - op: u32, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R> { - self.build().with_source_operand(op) - } - - pub fn append(self) { - let expr = self.build(); - let il = expr.function; - - il.instruction(expr); - } -} - -impl<'a, A, R> Liftable<'a, A> for ExpressionBuilder<'a, A, R> -where - A: 'a + Architecture, - R: ExpressionResultType, -{ - type Result = R; - - fn lift( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - expr: Self, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> { - debug_assert!(expr.function.handle == il.handle); - - expr.build() - } -} - -impl<'a, A> LiftableWithSize<'a, A> for ExpressionBuilder<'a, A, ValueExpr> -where - A: 'a + Architecture, -{ - fn lift_with_size( - il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, - expr: Self, - _size: usize, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - #[cfg(debug_assertions)] - { - use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_UNIMPL, LLIL_UNIMPL_MEM}; - - if expr.size != _size && ![LLIL_UNIMPL, LLIL_UNIMPL_MEM].contains(&expr.op) { - warn!( - "il @ {:x} attempted to lift {} byte expression builder as {} bytes", - il.current_address(), - expr.size, - _size - ); - } - } - - Liftable::lift(il, expr) - } -} - -macro_rules! no_arg_lifter { - ($name:ident, $op:ident, $result:ty) => { - pub fn $name(&self) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, $result> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, $op, 0, 0, 0, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - }; -} - -macro_rules! sized_no_arg_lifter { - ($name:ident, $op:ident, $result:ty) => { - pub fn $name(&self, size: usize) -> ExpressionBuilder<A, $result> { - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - ExpressionBuilder { - function: self, - op: $op, - size, - flags: 0, - op1: 0, - op2: 0, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - }; -} - -macro_rules! unsized_unary_op_lifter { - ($name:ident, $op:ident, $result:ty) => { - pub fn $name<'a, E>( - &'a self, - expr: E, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, $result> - where - E: Liftable<'a, A, Result = ValueExpr>, - { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - let expr = E::lift(self, expr); - - let expr_idx = unsafe { - BNLowLevelILAddExpr(self.handle, $op, 0, 0, expr.expr_idx as u64, 0, 0, 0) - }; - - Expression::new(self, expr_idx) - } - }; -} - -macro_rules! sized_unary_op_lifter { - ($name:ident, $op:ident, $result:ty) => { - pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, A, $result> - where - E: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - let expr = E::lift_with_size(self, expr, size); - - ExpressionBuilder { - function: self, - op: $op, - size, - flags: 0, - op1: expr.expr_idx as u64, - op2: 0, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - }; -} - -macro_rules! size_changing_unary_op_lifter { - ($name:ident, $op:ident, $result:ty) => { - pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, A, $result> - where - E: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - let expr = E::lift(self, expr); - - ExpressionBuilder { - function: self, - op: $op, - size, - flags: 0, - op1: expr.expr_idx as u64, - op2: 0, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - }; -} - -macro_rules! binary_op_lifter { - ($name:ident, $op:ident) => { - pub fn $name<'a, L, R>( - &'a self, - size: usize, - left: L, - right: R, - ) -> ExpressionBuilder<'a, A, ValueExpr> - where - L: LiftableWithSize<'a, A>, - R: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - let left = L::lift_with_size(self, left, size); - let right = R::lift_with_size(self, right, size); - - ExpressionBuilder { - function: self, - op: $op, - size, - flags: 0, - op1: left.expr_idx as u64, - op2: right.expr_idx as u64, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - }; -} - -macro_rules! binary_op_carry_lifter { - ($name:ident, $op:ident) => { - pub fn $name<'a, L, R, C>( - &'a self, - size: usize, - left: L, - right: R, - carry: C, - ) -> ExpressionBuilder<'a, A, ValueExpr> - where - L: LiftableWithSize<'a, A>, - R: LiftableWithSize<'a, A>, - C: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::$op; - - let left = L::lift_with_size(self, left, size); - let right = R::lift_with_size(self, right, size); - let carry = C::lift_with_size(self, carry, 0); - - ExpressionBuilder { - function: self, - op: $op, - size, - flags: 0, - op1: left.expr_idx as u64, - op2: right.expr_idx as u64, - op3: carry.expr_idx as u64, - op4: 0, - _ty: PhantomData, - } - } - }; -} - -impl<A> Function<A, Mutable, NonSSA<LiftedNonSSA>> -where - A: Architecture, -{ - pub const NO_INPUTS: [ExpressionBuilder<'static, A, ValueExpr>; 0] = []; - pub const NO_OUTPUTS: [Register<A::Register>; 0] = []; - - pub fn expression<'a, E: Liftable<'a, A>>( - &'a self, - expr: E, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, E::Result> { - E::lift(self, expr) - } - - pub fn instruction<'a, E: Liftable<'a, A>>(&'a self, expr: E) { - let expr = self.expression(expr); - - unsafe { - use binaryninjacore_sys::BNLowLevelILAddInstruction; - BNLowLevelILAddInstruction(self.handle, expr.expr_idx); - } - } - - pub unsafe fn replace_expression<'a, E: Liftable<'a, A>>( - &'a self, - replaced_expr_index: usize, - replacement: E, - ) { - use binaryninjacore_sys::BNGetLowLevelILExprCount; - use binaryninjacore_sys::BNReplaceLowLevelILExpr; - - if replaced_expr_index >= BNGetLowLevelILExprCount(self.handle) { - panic!( - "bad expr idx used: {} exceeds function bounds", - replaced_expr_index - ); - } - - let expr = self.expression(replacement); - BNReplaceLowLevelILExpr(self.handle, replaced_expr_index, expr.expr_idx); - } - - pub fn const_int( - &self, - size: usize, - val: u64, - ) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST; - - let expr_idx = - unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST, size, 0, val, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - - pub fn const_ptr_sized( - &self, - size: usize, - val: u64, - ) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST_PTR; - - let expr_idx = - unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST_PTR, size, 0, val, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - - pub fn const_ptr(&self, val: u64) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - self.const_ptr_sized(self.arch().address_size(), val) - } - - pub fn trap(&self, val: u64) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, VoidExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_TRAP; - - let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_TRAP, 0, 0, val, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - - no_arg_lifter!(unimplemented, LLIL_UNIMPL, ValueExpr); - no_arg_lifter!(undefined, LLIL_UNDEF, VoidExpr); - no_arg_lifter!(nop, LLIL_NOP, VoidExpr); - - no_arg_lifter!(no_ret, LLIL_NORET, VoidExpr); - no_arg_lifter!(syscall, LLIL_SYSCALL, VoidExpr); - no_arg_lifter!(bp, LLIL_BP, VoidExpr); - - unsized_unary_op_lifter!(call, LLIL_CALL, VoidExpr); - unsized_unary_op_lifter!(ret, LLIL_RET, VoidExpr); - unsized_unary_op_lifter!(jump, LLIL_JUMP, VoidExpr); - // JumpTo TODO - - pub fn if_expr<'a: 'b, 'b, C>( - &'a self, - cond: C, - t: &'b Label, - f: &'b Label, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, VoidExpr> - where - C: Liftable<'b, A, Result = ValueExpr>, - { - use binaryninjacore_sys::BNLowLevelILIf; - - let cond = C::lift(self, cond); - - let expr_idx = unsafe { - BNLowLevelILIf( - self.handle, - cond.expr_idx as u64, - &t.0 as *const _ as *mut _, - &f.0 as *const _ as *mut _, - ) - }; - - Expression::new(self, expr_idx) - } - - pub fn goto<'a: 'b, 'b>( - &'a self, - l: &'b Label, - ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, VoidExpr> { - use binaryninjacore_sys::BNLowLevelILGoto; - - let expr_idx = unsafe { BNLowLevelILGoto(self.handle, &l.0 as *const _ as *mut _) }; - - Expression::new(self, expr_idx) - } - - pub fn reg<R: Into<Register<A::Register>>>( - &self, - size: usize, - reg: R, - ) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG; - - // TODO verify valid id - let reg = match reg.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - - let expr_idx = - unsafe { BNLowLevelILAddExpr(self.handle, LLIL_REG, size, 0, reg as u64, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - - pub fn reg_split<H: Into<Register<A::Register>>, L: Into<Register<A::Register>>>( - &self, - size: usize, - hi_reg: H, - lo_reg: L, - ) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG_SPLIT; - - // TODO verify valid id - let hi_reg = match hi_reg.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - - // TODO verify valid id - let lo_reg = match lo_reg.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - - let expr_idx = unsafe { - BNLowLevelILAddExpr( - self.handle, - LLIL_REG_SPLIT, - size, - 0, - hi_reg as u64, - lo_reg as u64, - 0, - 0, - ) - }; - - Expression::new(self, expr_idx) - } - - pub fn set_reg<'a, R, E>( - &'a self, - size: usize, - dest_reg: R, - expr: E, - ) -> ExpressionBuilder<'a, A, VoidExpr> - where - R: Into<Register<A::Register>>, - E: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG; - - // TODO verify valid id - let dest_reg = match dest_reg.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - - let expr = E::lift_with_size(self, expr, size); - - ExpressionBuilder { - function: self, - op: LLIL_SET_REG, - size, - flags: 0, - op1: dest_reg as u64, - op2: expr.expr_idx as u64, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - - pub fn set_reg_split<'a, H, L, E>( - &'a self, - size: usize, - hi_reg: H, - lo_reg: L, - expr: E, - ) -> ExpressionBuilder<'a, A, VoidExpr> - where - H: Into<Register<A::Register>>, - L: Into<Register<A::Register>>, - E: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG_SPLIT; - - // TODO verify valid id - let hi_reg = match hi_reg.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - - // TODO verify valid id - let lo_reg = match lo_reg.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - - let expr = E::lift_with_size(self, expr, size); - - ExpressionBuilder { - function: self, - op: LLIL_SET_REG_SPLIT, - size, - flags: 0, - op1: hi_reg as u64, - op2: lo_reg as u64, - op3: expr.expr_idx as u64, - op4: 0, - _ty: PhantomData, - } - } - - pub fn flag(&self, flag: A::Flag) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG; - - // TODO verify valid id - let expr_idx = - unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG, 0, 0, flag.id() as u64, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - - pub fn flag_cond( - &self, - cond: FlagCondition, - ) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_COND; - - // TODO verify valid id - let expr_idx = - unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG_COND, 0, 0, cond as u64, 0, 0, 0) }; - - Expression::new(self, expr_idx) - } - - pub fn flag_group( - &self, - group: A::FlagGroup, - ) -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> { - use binaryninjacore_sys::BNLowLevelILAddExpr; - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_GROUP; - - // TODO verify valid id - let expr_idx = unsafe { - BNLowLevelILAddExpr( - self.handle, - LLIL_FLAG_GROUP, - 0, - 0, - group.id() as u64, - 0, - 0, - 0, - ) - }; - - Expression::new(self, expr_idx) - } - - pub fn set_flag<'a, E>( - &'a self, - dest_flag: A::Flag, - expr: E, - ) -> ExpressionBuilder<'a, A, VoidExpr> - where - E: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_FLAG; - - // TODO verify valid id - - let expr = E::lift_with_size(self, expr, 0); - - ExpressionBuilder { - function: self, - op: LLIL_SET_FLAG, - size: 0, - flags: 0, - op1: dest_flag.id() as u64, - op2: expr.expr_idx as u64, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - - /* - * TODO - FlagBit(usize, Flag<A>, u64), - */ - - pub fn load<'a, E>(&'a self, size: usize, source_mem: E) -> ExpressionBuilder<'a, A, ValueExpr> - where - E: Liftable<'a, A, Result = ValueExpr>, - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_LOAD; - - let expr = E::lift(self, source_mem); - - ExpressionBuilder { - function: self, - op: LLIL_LOAD, - size, - flags: 0, - op1: expr.expr_idx as u64, - op2: 0, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - - pub fn store<'a, D, V>( - &'a self, - size: usize, - dest_mem: D, - value: V, - ) -> ExpressionBuilder<'a, A, VoidExpr> - where - D: Liftable<'a, A, Result = ValueExpr>, - V: LiftableWithSize<'a, A>, - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_STORE; - - let dest_mem = D::lift(self, dest_mem); - let value = V::lift_with_size(self, value, size); - - ExpressionBuilder { - function: self, - op: LLIL_STORE, - size, - flags: 0, - op1: dest_mem.expr_idx as u64, - op2: value.expr_idx as u64, - op3: 0, - op4: 0, - _ty: PhantomData, - } - } - - pub fn intrinsic<'a, O, OL, I, P, PL>( - &'a self, - outputs: OL, - intrinsic: I, - inputs: PL, - ) -> ExpressionBuilder<'a, A, VoidExpr> - where - O: Into<Register<A::Register>>, - OL: IntoIterator<Item = O>, - I: Into<A::Intrinsic>, - P: Liftable<'a, A, Result = ValueExpr>, - PL: IntoIterator<Item = P>, - { - use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_CALL_PARAM, LLIL_INTRINSIC}; - use binaryninjacore_sys::{BNLowLevelILAddExpr, BNLowLevelILAddOperandList}; - - let mut outputs: Vec<u64> = outputs - .into_iter() - .map(|output| { - // TODO verify valid id - let output = match output.into() { - Register::ArchReg(r) => r.id(), - Register::Temp(r) => 0x8000_0000 | r, - }; - output as u64 - }) - .collect(); - let output_expr_idx = - unsafe { BNLowLevelILAddOperandList(self.handle, outputs.as_mut_ptr(), outputs.len()) }; - - let intrinsic: A::Intrinsic = intrinsic.into(); - - let mut inputs: Vec<u64> = inputs - .into_iter() - .map(|input| { - let input = P::lift(self, input); - input.expr_idx as u64 - }) - .collect(); - let input_list_expr_idx = - unsafe { BNLowLevelILAddOperandList(self.handle, inputs.as_mut_ptr(), inputs.len()) }; - let input_expr_idx = unsafe { - BNLowLevelILAddExpr( - self.handle, - LLIL_CALL_PARAM, - 0, - 0, - inputs.len() as u64, - input_list_expr_idx as u64, - 0, - 0, - ) - }; - - ExpressionBuilder { - function: self, - op: LLIL_INTRINSIC, - size: 0, - flags: 0, - op1: outputs.len() as u64, - op2: output_expr_idx as u64, - op3: intrinsic.id() as u64, - op4: input_expr_idx as u64, - _ty: PhantomData, - } - } - - sized_unary_op_lifter!(push, LLIL_PUSH, VoidExpr); - sized_no_arg_lifter!(pop, LLIL_POP, ValueExpr); - - size_changing_unary_op_lifter!(unimplemented_mem, LLIL_UNIMPL_MEM, ValueExpr); - - sized_unary_op_lifter!(neg, LLIL_NEG, ValueExpr); - sized_unary_op_lifter!(not, LLIL_NOT, ValueExpr); - - size_changing_unary_op_lifter!(sx, LLIL_SX, ValueExpr); - size_changing_unary_op_lifter!(zx, LLIL_ZX, ValueExpr); - size_changing_unary_op_lifter!(low_part, LLIL_LOW_PART, ValueExpr); - - binary_op_lifter!(add, LLIL_ADD); - binary_op_lifter!(add_overflow, LLIL_ADD_OVERFLOW); - binary_op_lifter!(sub, LLIL_SUB); - binary_op_lifter!(and, LLIL_AND); - binary_op_lifter!(or, LLIL_OR); - binary_op_lifter!(xor, LLIL_XOR); - binary_op_lifter!(lsl, LLIL_LSL); - binary_op_lifter!(lsr, LLIL_LSR); - binary_op_lifter!(asr, LLIL_ASR); - - binary_op_lifter!(rol, LLIL_ROL); - binary_op_lifter!(rlc, LLIL_RLC); - binary_op_lifter!(ror, LLIL_ROR); - binary_op_lifter!(rrc, LLIL_RRC); - binary_op_lifter!(mul, LLIL_MUL); - binary_op_lifter!(muls_dp, LLIL_MULS_DP); - binary_op_lifter!(mulu_dp, LLIL_MULU_DP); - binary_op_lifter!(divs, LLIL_DIVS); - binary_op_lifter!(divu, LLIL_DIVU); - binary_op_lifter!(mods, LLIL_MODS); - binary_op_lifter!(modu, LLIL_MODU); - - binary_op_carry_lifter!(adc, LLIL_ADC); - binary_op_carry_lifter!(sbb, LLIL_SBB); - - /* - DivsDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>), - DivuDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>), - ModsDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>), - ModuDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>), - */ - - // FlagCond(u32), // TODO - - binary_op_lifter!(cmp_e, LLIL_CMP_E); - binary_op_lifter!(cmp_ne, LLIL_CMP_NE); - binary_op_lifter!(cmp_slt, LLIL_CMP_SLT); - binary_op_lifter!(cmp_ult, LLIL_CMP_ULT); - binary_op_lifter!(cmp_sle, LLIL_CMP_SLE); - binary_op_lifter!(cmp_ule, LLIL_CMP_ULE); - binary_op_lifter!(cmp_sge, LLIL_CMP_SGE); - binary_op_lifter!(cmp_uge, LLIL_CMP_UGE); - binary_op_lifter!(cmp_sgt, LLIL_CMP_SGT); - binary_op_lifter!(cmp_ugt, LLIL_CMP_UGT); - binary_op_lifter!(test_bit, LLIL_TEST_BIT); - - // TODO no flags - size_changing_unary_op_lifter!(bool_to_int, LLIL_BOOL_TO_INT, ValueExpr); - - binary_op_lifter!(fadd, LLIL_FADD); - binary_op_lifter!(fsub, LLIL_FSUB); - binary_op_lifter!(fmul, LLIL_FMUL); - binary_op_lifter!(fdiv, LLIL_FDIV); - sized_unary_op_lifter!(fsqrt, LLIL_FSQRT, ValueExpr); - sized_unary_op_lifter!(fneg, LLIL_FNEG, ValueExpr); - sized_unary_op_lifter!(fabs, LLIL_FABS, ValueExpr); - sized_unary_op_lifter!(float_to_int, LLIL_FLOAT_TO_INT, ValueExpr); - sized_unary_op_lifter!(int_to_float, LLIL_INT_TO_FLOAT, ValueExpr); - sized_unary_op_lifter!(float_conv, LLIL_FLOAT_CONV, ValueExpr); - sized_unary_op_lifter!(round_to_int, LLIL_ROUND_TO_INT, ValueExpr); - sized_unary_op_lifter!(floor, LLIL_FLOOR, ValueExpr); - sized_unary_op_lifter!(ceil, LLIL_CEIL, ValueExpr); - sized_unary_op_lifter!(ftrunc, LLIL_FTRUNC, ValueExpr); - binary_op_lifter!(fcmp_e, LLIL_FCMP_E); - binary_op_lifter!(fcmp_ne, LLIL_FCMP_NE); - binary_op_lifter!(fcmp_lt, LLIL_FCMP_LT); - binary_op_lifter!(fcmp_le, LLIL_FCMP_LE); - binary_op_lifter!(fcmp_ge, LLIL_FCMP_GE); - binary_op_lifter!(fcmp_gt, LLIL_FCMP_GT); - binary_op_lifter!(fcmp_o, LLIL_FCMP_O); - binary_op_lifter!(fcmp_uo, LLIL_FCMP_UO); - - pub fn current_address(&self) -> u64 { - use binaryninjacore_sys::BNLowLevelILGetCurrentAddress; - unsafe { BNLowLevelILGetCurrentAddress(self.handle) } - } - - pub fn set_current_address<L: Into<Location>>(&self, loc: L) { - use binaryninjacore_sys::BNLowLevelILSetCurrentAddress; - - let loc: Location = loc.into(); - let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref()); - - unsafe { - BNLowLevelILSetCurrentAddress(self.handle, arch.0, loc.addr); - } - } - - pub fn label_for_address<L: Into<Location>>(&self, loc: L) -> Option<&Label> { - use binaryninjacore_sys::BNGetLowLevelILLabelForAddress; - - let loc: Location = loc.into(); - let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref()); - - let res = unsafe { BNGetLowLevelILLabelForAddress(self.handle, arch.0, loc.addr) }; - - if res.is_null() { - None - } else { - Some(unsafe { &*(res as *mut Label) }) - } - } - - pub fn mark_label(&self, label: &mut Label) { - use binaryninjacore_sys::BNLowLevelILMarkLabel; - - unsafe { - BNLowLevelILMarkLabel(self.handle, &mut label.0 as *mut _); - } - } -} - -use binaryninjacore_sys::BNLowLevelILLabel; - -#[repr(C)] -pub struct Label(BNLowLevelILLabel); -impl Label { - pub fn new() -> Self { - use binaryninjacore_sys::BNLowLevelILInitLabel; - - unsafe { - // This is one instance where it'd be easy to use mem::MaybeUninit, but *shrug* this is easier - let mut res = Label(mem::zeroed()); - BNLowLevelILInitLabel(&mut res.0 as *mut _); - res - } - } -} - -impl Default for Label { - fn default() -> Self { - Self::new() - } -} diff --git a/rust/src/llil/mod.rs b/rust/src/llil/mod.rs deleted file mode 100644 index b9424e86..00000000 --- a/rust/src/llil/mod.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::fmt; - -// TODO : provide some way to forbid emitting register reads for certain registers -// also writing for certain registers (e.g. zero register must prohibit il.set_reg and il.reg -// (replace with nop or const(0) respectively) -// requirements on load/store memory address sizes? -// can reg/set_reg be used with sizes that differ from what is in BNRegisterInfo? - -use crate::architecture::Architecture; -use crate::architecture::Register as ArchReg; -use crate::function::Location; - -mod block; -mod expression; -mod function; -mod instruction; -mod lifting; -pub mod operation; - -pub use self::expression::*; -pub use self::function::*; -pub use self::instruction::*; -pub use self::lifting::get_default_flag_cond_llil; -pub use self::lifting::get_default_flag_write_llil; -pub use self::lifting::{ - ExpressionBuilder, FlagWriteOp, Label, Liftable, LiftableWithSize, RegisterOrConstant, -}; - -pub use self::block::Block as LowLevelBlock; -pub use self::block::BlockIter as LowLevelBlockIter; - -pub type Lifter<Arch> = Function<Arch, Mutable, NonSSA<LiftedNonSSA>>; -pub type LiftedFunction<Arch> = Function<Arch, Finalized, NonSSA<LiftedNonSSA>>; -pub type LiftedExpr<'a, Arch> = Expression<'a, Arch, Mutable, NonSSA<LiftedNonSSA>, ValueExpr>; -pub type RegularFunction<Arch> = Function<Arch, Finalized, NonSSA<RegularNonSSA>>; -pub type SSAFunction<Arch> = Function<Arch, Finalized, SSA>; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum Register<R: ArchReg> { - ArchReg(R), - Temp(u32), -} - -impl<R: ArchReg> Register<R> { - fn id(&self) -> u32 { - match *self { - Register::ArchReg(ref r) => r.id(), - Register::Temp(id) => 0x8000_0000 | id, - } - } -} - -impl<R: ArchReg> fmt::Debug for Register<R> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Register::ArchReg(ref r) => write!(f, "{}", r.name().as_ref()), - Register::Temp(id) => write!(f, "temp{}", id), - } - } -} - -#[derive(Copy, Clone, Debug)] -pub enum SSARegister<R: ArchReg> { - Full(Register<R>, u32), // no such thing as partial access to a temp register, I think - Partial(R, u32, R), // partial accesses only possible for arch registers, I think -} - -impl<R: ArchReg> SSARegister<R> { - pub fn version(&self) -> u32 { - match *self { - SSARegister::Full(_, ver) | SSARegister::Partial(_, ver, _) => ver, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum VisitorAction { - Descend, - Sibling, - Halt, -} diff --git a/rust/src/llil/operation.rs b/rust/src/llil/operation.rs deleted file mode 100644 index b65dfa8c..00000000 --- a/rust/src/llil/operation.rs +++ /dev/null @@ -1,825 +0,0 @@ -// Copyright 2021-2024 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use binaryninjacore_sys::{BNGetLowLevelILByIndex, BNLowLevelILInstruction}; - -use std::collections::BTreeMap; -use std::marker::PhantomData; -use std::mem; - -use super::*; - -pub struct Operation<'func, A, M, F, O> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, - O: OperationArguments, -{ - pub(crate) function: &'func Function<A, M, F>, - pub(crate) op: BNLowLevelILInstruction, - _args: PhantomData<O>, -} - -impl<'func, A, M, F, O> Operation<'func, A, M, F, O> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, - O: OperationArguments, -{ - pub(crate) fn new(function: &'func Function<A, M, F>, op: BNLowLevelILInstruction) -> Self { - Self { - function, - op, - _args: PhantomData, - } - } - - pub fn address(&self) -> u64 { - self.op.address - } -} - -impl<'func, A, M, O> Operation<'func, A, M, NonSSA<LiftedNonSSA>, O> -where - A: 'func + Architecture, - M: FunctionMutability, - O: OperationArguments, -{ - pub fn flag_write(&self) -> Option<A::FlagWrite> { - match self.op.flags { - 0 => None, - id => self.function.arch().flag_write_from_id(id), - } - } -} - -// LLIL_NOP, LLIL_NORET, LLIL_BP, LLIL_UNDEF, LLIL_UNIMPL -pub struct NoArgs; - -// LLIL_POP -pub struct Pop; - -impl<'func, A, M, F> Operation<'func, A, M, F, Pop> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } -} - -// LLIL_SYSCALL, LLIL_SYSCALL_SSA -pub struct Syscall; - -// LLIL_INTRINSIC, LLIL_INTRINSIC_SSA -pub struct Intrinsic; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Intrinsic> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - // TODO: Support register and expression lists - pub fn intrinsic(&self) -> Option<A::Intrinsic> { - let raw_id = self.op.operands[2] as u32; - self.function.arch().intrinsic_from_id(raw_id) - } -} - -// LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA -pub struct SetReg; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, SetReg> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn dest_reg(&self) -> Register<A::Register> { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - Register::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(raw_id) - .map(Register::ArchReg) - .unwrap_or_else(|| { - error!( - "got garbage register from LLIL_SET_REG @ 0x{:x}", - self.op.address - ); - - Register::Temp(0) - }) - } - } - - pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } -} - -// LLIL_SET_REG_SPLIT, LLIL_SET_REG_SPLIT_SSA -pub struct SetRegSplit; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, SetRegSplit> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn dest_reg_high(&self) -> Register<A::Register> { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - Register::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(raw_id) - .map(Register::ArchReg) - .unwrap_or_else(|| { - error!( - "got garbage register from LLIL_SET_REG_SPLIT @ 0x{:x}", - self.op.address - ); - - Register::Temp(0) - }) - } - } - - pub fn dest_reg_low(&self) -> Register<A::Register> { - let raw_id = self.op.operands[1] as u32; - - if raw_id >= 0x8000_0000 { - Register::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(raw_id) - .map(Register::ArchReg) - .unwrap_or_else(|| { - error!( - "got garbage register from LLIL_SET_REG_SPLIT @ 0x{:x}", - self.op.address - ); - - Register::Temp(0) - }) - } - } - - pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[2] as usize) - } -} - -// LLIL_SET_FLAG, LLIL_SET_FLAG_SSA -pub struct SetFlag; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, SetFlag> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } -} - -// LLIL_LOAD, LLIL_LOAD_SSA -pub struct Load; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Load> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn source_mem_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } -} - -// LLIL_STORE, LLIL_STORE_SSA -pub struct Store; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Store> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn dest_mem_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn source_expr(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } -} - -// LLIL_REG, LLIL_REG_SSA, LLIL_REG_SSA_PARTIAL -pub struct Reg; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Reg> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn source_reg(&self) -> Register<A::Register> { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - Register::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(raw_id) - .map(Register::ArchReg) - .unwrap_or_else(|| { - error!( - "got garbage register from LLIL_REG @ 0x{:x}", - self.op.address - ); - - Register::Temp(0) - }) - } - } -} - -// LLIL_REG_SPLIT -pub struct RegSplit; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, RegSplit> - where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn low_reg(&self) -> Register<A::Register> { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - Register::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(raw_id) - .map(Register::ArchReg) - .unwrap_or_else(|| { - error!( - "got garbage register from LLIL_REG @ 0x{:x}", - self.op.address - ); - - Register::Temp(0) - }) - } - } - - pub fn high_reg(&self) -> Register<A::Register> { - let raw_id = self.op.operands[1] as u32; - - if raw_id >= 0x8000_0000 { - Register::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(raw_id) - .map(Register::ArchReg) - .unwrap_or_else(|| { - error!( - "got garbage register from LLIL_REG @ 0x{:x}", - self.op.address - ); - - Register::Temp(0) - }) - } - } -} - -// LLIL_FLAG, LLIL_FLAG_SSA -pub struct Flag; - -// LLIL_FLAG_BIT, LLIL_FLAG_BIT_SSA -pub struct FlagBit; - -// LLIL_JUMP -pub struct Jump; - -impl<'func, A, M, F> Operation<'func, A, M, F, Jump> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn target(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } -} - -// LLIL_JUMP_TO -pub struct JumpTo; - -struct TargetListIter<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - function: &'func Function<A, M, F>, - cursor: BNLowLevelILInstruction, - cursor_operand: usize, -} - -impl<'func, A, M, F> TargetListIter<'func, A, M, F> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - fn next(&mut self) -> u64 { - if self.cursor_operand >= 3 { - self.cursor = unsafe { - BNGetLowLevelILByIndex(self.function.handle, self.cursor.operands[3] as usize) - }; - self.cursor_operand = 0; - } - let result = self.cursor.operands[self.cursor_operand]; - self.cursor_operand += 1; - result - } -} - -impl<'func, A, M, F> Operation<'func, A, M, F, JumpTo> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn target(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn target_list(&self) -> BTreeMap<u64, usize> { - let mut result = BTreeMap::new(); - let count = self.op.operands[1] as usize / 2; - let mut list = TargetListIter { - function: self.function, - cursor: unsafe { - BNGetLowLevelILByIndex(self.function.handle, self.op.operands[2] as usize) - }, - cursor_operand: 0, - }; - - for _ in 0..count { - let value = list.next(); - let target = list.next() as usize; - result.insert(value, target); - } - - result - } -} - -// LLIL_CALL, LLIL_CALL_SSA -pub struct Call; - -impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Call> -where - A: 'func + Architecture, - M: FunctionMutability, - V: NonSSAVariant, -{ - pub fn target(&self) -> Expression<'func, A, M, NonSSA<V>, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn stack_adjust(&self) -> Option<u64> { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CALL_STACK_ADJUST; - - if self.op.operation == LLIL_CALL_STACK_ADJUST { - Some(self.op.operands[1]) - } else { - None - } - } -} - -// LLIL_RET -pub struct Ret; - -impl<'func, A, M, F> Operation<'func, A, M, F, Ret> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn target(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } -} - -// LLIL_IF -pub struct If; - -impl<'func, A, M, F> Operation<'func, A, M, F, If> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn condition(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn true_target(&self) -> Instruction<'func, A, M, F> { - Instruction { - function: self.function, - instr_idx: self.op.operands[1] as usize, - } - } - - pub fn true_target_idx(&self) -> usize { - self.op.operands[1] as usize - } - - pub fn false_target(&self) -> Instruction<'func, A, M, F> { - Instruction { - function: self.function, - instr_idx: self.op.operands[2] as usize, - } - } - - pub fn false_target_idx(&self) -> usize { - self.op.operands[2] as usize - } -} - -// LLIL_GOTO -pub struct Goto; - -impl<'func, A, M, F> Operation<'func, A, M, F, Goto> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn target(&self) -> Instruction<'func, A, M, F> { - Instruction { - function: self.function, - instr_idx: self.op.operands[0] as usize, - } - } - - pub fn target_idx(&self) -> usize { - self.op.operands[0] as usize - } -} - -// LLIL_FLAG_COND -pub struct FlagCond; - -// LLIL_FLAG_GROUP -pub struct FlagGroup; - -impl<'func, A, M> Operation<'func, A, M, NonSSA<LiftedNonSSA>, FlagGroup> -where - A: 'func + Architecture, - M: FunctionMutability, -{ - pub fn flag_group(&self) -> A::FlagGroup { - let id = self.op.operands[0] as u32; - self.function.arch().flag_group_from_id(id).unwrap() - } -} - -// LLIL_TRAP -pub struct Trap; - -impl<'func, A, M, F> Operation<'func, A, M, F, Trap> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn vector(&self) -> u64 { - self.op.operands[0] - } -} - -// LLIL_REG_PHI -pub struct RegPhi; - -// LLIL_FLAG_PHI -pub struct FlagPhi; - -// LLIL_MEM_PHI -pub struct MemPhi; - -// LLIL_CONST, LLIL_CONST_PTR -pub struct Const; - -impl<'func, A, M, F> Operation<'func, A, M, F, Const> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn value(&self) -> u64 { - #[cfg(debug_assertions)] - { - let raw = self.op.operands[0] as i64; - - let is_safe = match raw.overflowing_shr(self.op.size as u32 * 8) { - (_, true) => true, - (res, false) => [-1, 0].contains(&res), - }; - - if !is_safe { - error!( - "il expr @ {:x} contains constant 0x{:x} as {} byte value (doesn't fit!)", - self.op.address, self.op.operands[0], self.op.size - ); - } - } - - let mut mask = -1i64 as u64; - - if self.op.size < mem::size_of::<u64>() { - mask <<= self.op.size * 8; - mask = !mask; - } - - self.op.operands[0] & mask - } -} - -// LLIL_EXTERN_PTR -pub struct Extern; - -impl<'func, A, M, F> Operation<'func, A, M, F, Extern> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn value(&self) -> u64 { - #[cfg(debug_assertions)] - { - let raw = self.op.operands[0] as i64; - - let is_safe = match raw.overflowing_shr(self.op.size as u32 * 8) { - (_, true) => true, - (res, false) => [-1, 0].contains(&res), - }; - - if !is_safe { - error!( - "il expr @ {:x} contains extern 0x{:x} as {} byte value (doesn't fit!)", - self.op.address, self.op.operands[0], self.op.size - ); - } - } - - let mut mask = -1i64 as u64; - - if self.op.size < mem::size_of::<u64>() { - mask <<= self.op.size * 8; - mask = !mask; - } - - self.op.operands[0] & mask - } -} - -// LLIL_ADD, LLIL_SUB, LLIL_AND, LLIL_OR -// LLIL_XOR, LLIL_LSL, LLIL_LSR, LLIL_ASR -// LLIL_ROL, LLIL_ROR, LLIL_MUL, LLIL_MULU_DP, -// LLIL_MULS_DP, LLIL_DIVU, LLIL_DIVS, LLIL_MODU, -// LLIL_MODS -pub struct BinaryOp; - -impl<'func, A, M, F> Operation<'func, A, M, F, BinaryOp> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn left(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } -} - -// LLIL_ADC, LLIL_SBB, LLIL_RLC, LLIL_RRC -pub struct BinaryOpCarry; - -impl<'func, A, M, F> Operation<'func, A, M, F, BinaryOpCarry> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn left(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } - - pub fn carry(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[2] as usize) - } -} - -// LLIL_DIVS_DP, LLIL_DIVU_DP, LLIL_MODU_DP, LLIL_MODS_DP -pub struct DoublePrecDivOp; - -impl<'func, A, M, F> Operation<'func, A, M, F, DoublePrecDivOp> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn high(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn low(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } - - pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[2] as usize) - } -} - -// LLIL_PUSH, LLIL_NEG, LLIL_NOT, LLIL_SX, -// LLIL_ZX, LLIL_LOW_PART, LLIL_BOOL_TO_INT, LLIL_UNIMPL_MEM -pub struct UnaryOp; - -impl<'func, A, M, F> Operation<'func, A, M, F, UnaryOp> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn operand(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } -} - -// LLIL_CMP_X -pub struct Condition; - -impl<'func, A, M, F> Operation<'func, A, M, F, Condition> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn left(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } - - pub fn right(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[1] as usize) - } -} - -// LLIL_UNIMPL_MEM -pub struct UnimplMem; - -impl<'func, A, M, F> Operation<'func, A, M, F, UnimplMem> -where - A: 'func + Architecture, - M: FunctionMutability, - F: FunctionForm, -{ - pub fn size(&self) -> usize { - self.op.size - } - - pub fn mem_expr(&self) -> Expression<'func, A, M, F, ValueExpr> { - Expression::new(self.function, self.op.operands[0] as usize) - } -} - -// TODO TEST_BIT - -pub trait OperationArguments: 'static {} - -impl OperationArguments for NoArgs {} -impl OperationArguments for Pop {} -impl OperationArguments for Syscall {} -impl OperationArguments for Intrinsic {} -impl OperationArguments for SetReg {} -impl OperationArguments for SetRegSplit {} -impl OperationArguments for SetFlag {} -impl OperationArguments for Load {} -impl OperationArguments for Store {} -impl OperationArguments for Reg {} -impl OperationArguments for RegSplit {} -impl OperationArguments for Flag {} -impl OperationArguments for FlagBit {} -impl OperationArguments for Jump {} -impl OperationArguments for JumpTo {} -impl OperationArguments for Call {} -impl OperationArguments for Ret {} -impl OperationArguments for If {} -impl OperationArguments for Goto {} -impl OperationArguments for FlagCond {} -impl OperationArguments for FlagGroup {} -impl OperationArguments for Trap {} -impl OperationArguments for RegPhi {} -impl OperationArguments for FlagPhi {} -impl OperationArguments for MemPhi {} -impl OperationArguments for Const {} -impl OperationArguments for Extern {} -impl OperationArguments for BinaryOp {} -impl OperationArguments for BinaryOpCarry {} -impl OperationArguments for DoublePrecDivOp {} -impl OperationArguments for UnaryOp {} -impl OperationArguments for Condition {} -impl OperationArguments for UnimplMem {} |
