// Copyright 2021-2022 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::BNLowLevelILFunction; use binaryninjacore_sys::BNNewLowLevelILFunctionReference; use std::borrow::Borrow; use std::marker::PhantomData; 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); pub trait FunctionForm: 'static {} impl FunctionForm for SSA {} impl FunctionForm for NonSSA {} pub struct Function { pub(crate) borrower: A::Handle, pub(crate) handle: *mut BNLowLevelILFunction, _arch: PhantomData<*mut A>, _mutability: PhantomData, _form: PhantomData, } unsafe impl Send for Function {} unsafe impl Sync for Function {} impl Eq for Function {} impl PartialEq for Function { fn eq(&self, rhs: &Self) -> bool { self.handle == rhs.handle } } use std::hash::{Hash, Hasher}; impl Hash for Function { fn hash(&self, state: &mut H) { self.handle.hash(state); } } impl<'func, A, M, F> Function 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) fn arch(&self) -> &A { self.borrower.borrow() } pub fn instruction_at>(&self, loc: L) -> Option> { 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: instr_idx, }) } } } pub fn instruction_from_idx(&self, instr_idx: usize) -> Instruction { unsafe { use binaryninjacore_sys::BNGetLowLevelILInstructionCount; if instr_idx >= BNGetLowLevelILInstructionCount(self.handle) { panic!("instruction index {} out of bounds", instr_idx); } Instruction { function: self, instr_idx: instr_idx, } } } pub fn instruction_count(&self) -> usize { unsafe { use binaryninjacore_sys::BNGetLowLevelILInstructionCount; BNGetLowLevelILInstructionCount(self.handle) } } } // 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 where A: 'func + Architecture, F: FunctionForm, { pub fn basic_blocks(&self) -> Array>> { 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) } } } impl<'func, A, M, F> ToOwned for Function where A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { type Owned = Ref; fn to_owned(&self) -> Self::Owned { unsafe { RefCountable::inc_ref(self) } } } unsafe impl<'func, A, M, F> RefCountable for Function where A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { unsafe fn inc_ref(handle: &Self) -> Ref { 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 where A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "", self.handle) } }