summaryrefslogtreecommitdiff
path: root/rust/src/llil
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/llil')
-rw-r--r--rust/src/llil/block.rs103
-rw-r--r--rust/src/llil/expression.rs851
-rw-r--r--rust/src/llil/function.rs255
-rw-r--r--rust/src/llil/instruction.rs209
-rw-r--r--rust/src/llil/lifting.rs1492
-rw-r--r--rust/src/llil/mod.rs95
-rw-r--r--rust/src/llil/operation.rs825
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 {}