diff options
| author | KyleMiles <krm504@nyu.edu> | 2021-01-21 18:35:20 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:07:07 +0000 |
| commit | 2fcacc55d5466a7d17bdc0b3ce988772aa6d0653 (patch) | |
| tree | 9d0f2ba19117843575936f2b93e0b6a578a84dc8 /rust/src | |
| parent | a0da07c5c2860a5bd69921d38e438bbc1d43912f (diff) | |
cargo fmt and all my changes
Diffstat (limited to 'rust/src')
30 files changed, 3792 insertions, 1951 deletions
diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 18dd5e82..5db7232c 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -1,26 +1,40 @@ +// Copyright 2021 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. + // container abstraction to avoid Vec<> (want CoreArchFlagList, CoreArchRegList) // RegisterInfo purge use binaryninjacore_sys::*; -use std::ffi::{CString, CStr}; -use std::ptr; -use std::ops::Drop; use std::borrow::{Borrow, Cow}; -use std::slice; -use std::ops; -use std::mem::zeroed; -use std::hash::Hash; use std::collections::HashMap; +use std::ffi::{CStr, CString}; +use std::hash::Hash; +use std::mem::zeroed; +use std::ops; +use std::ops::Drop; +use std::ptr; +use std::slice; -use crate::{BranchType, Endianness}; use crate::callingconvention::CallingConvention; use crate::platform::Platform; +use crate::{BranchType, Endianness}; -use crate::llil::{Lifter, LiftedExpr, FlagWriteOp}; -use crate::llil::{get_default_flag_write_llil, get_default_flag_cond_llil}; +use crate::llil::{get_default_flag_cond_llil, get_default_flag_write_llil}; +use crate::llil::{FlagWriteOp, LiftedExpr, Lifter}; -use crate::string::*; use crate::rc::*; +use crate::string::*; pub enum BranchInfo { Unconditional(u64), @@ -32,6 +46,7 @@ pub enum BranchInfo { Indirect, Exception, Unresolved, + UserDefined, } pub struct BranchIter<'a>(&'a InstructionInfo, ops::Range<usize>); @@ -45,7 +60,11 @@ impl<'a> Iterator for BranchIter<'a> { Some(i) => { let target = (self.0).0.branchTarget[i]; let arch = (self.0).0.branchArch[i]; - let arch = if arch.is_null() { None } else { Some(CoreArchitecture(arch)) }; + let arch = if arch.is_null() { + None + } else { + Some(CoreArchitecture(arch)) + }; let res = match (self.0).0.branchType[i] { UnconditionalBranch => BranchInfo::Unconditional(target), @@ -57,6 +76,7 @@ impl<'a> Iterator for BranchIter<'a> { IndirectBranch => BranchInfo::Indirect, ExceptionBranch => BranchInfo::Exception, UnresolvedBranch => BranchInfo::Unresolved, + UserDefinedBranch => BranchInfo::UserDefined, }; Some((res, arch)) @@ -70,23 +90,29 @@ impl<'a> Iterator for BranchIter<'a> { pub struct InstructionInfo(BNInstructionInfo); impl InstructionInfo { pub fn new(len: usize, branch_delay: bool) -> Self { - InstructionInfo ( - BNInstructionInfo { - length: len, - archTransitionByTargetAddr: false, - branchDelay: branch_delay, - branchCount: 0usize, - branchType: [BranchType::UnresolvedBranch; 3], - branchTarget: [0u64; 3], - branchArch: [ptr::null_mut(); 3], - } - ) + InstructionInfo(BNInstructionInfo { + length: len, + archTransitionByTargetAddr: false, + branchDelay: branch_delay, + branchCount: 0usize, + branchType: [BranchType::UnresolvedBranch; 3], + branchTarget: [0u64; 3], + branchArch: [ptr::null_mut(); 3], + }) + } + + pub fn len(&self) -> usize { + self.0.length + } + pub fn branch_count(&self) -> usize { + self.0.branchCount + } + pub fn branch_delay(&self) -> bool { + self.0.branchDelay + } + pub fn branches(&self) -> BranchIter { + BranchIter(self, 0..self.branch_count()) } - - pub fn len(&self) -> usize { self.0.length } - pub fn branch_count(&self) -> usize { self.0.branchCount } - pub fn branch_delay(&self) -> bool { self.0.branchDelay } - pub fn branches(&self) -> BranchIter { BranchIter(self, 0 .. self.branch_count()) } pub fn allow_arch_transition_by_target_addr(&mut self, transition: bool) { self.0.archTransitionByTargetAddr = transition; @@ -118,6 +144,7 @@ impl InstructionInfo { BranchInfo::Indirect => BranchType::IndirectBranch, BranchInfo::Exception => BranchType::ExceptionBranch, BranchInfo::Unresolved => BranchType::UnresolvedBranch, + BranchInfo::UserDefined => BranchType::UserDefinedBranch, }; self.0.branchType[idx] = ty; @@ -138,7 +165,7 @@ pub enum InstructionTextTokenContents { Instruction, OperandSeparator, Register, - Integer(u64), // TODO size? + Integer(u64), // TODO size? PossibleAddress(u64), // TODO size? BeginMemoryOperand, EndMemoryOperand, @@ -165,16 +192,14 @@ impl InstructionTextToken { match contents { Integer(v) => res.value = v, - PossibleAddress(v) | - CodeRelativeAddress(v) => { + PossibleAddress(v) | CodeRelativeAddress(v) => { res.value = v; res.address = v; } - _ => {}, + _ => {} } res.type_ = match contents { - Text => TextToken, Instruction => InstructionToken, OperandSeparator => OperandSeparatorToken, @@ -234,21 +259,19 @@ impl InstructionTextToken { impl Clone for InstructionTextToken { fn clone(&self) -> Self { - InstructionTextToken ( - BNInstructionTextToken { - type_: self.0.type_, - context: self.0.context, - address: self.0.address, - size: self.0.size, - operand: self.0.operand, - value: self.0.value, - width: 0, - text: self.text().to_owned().into_raw(), - confidence: 0xff, - typeNames: ptr::null_mut(), - namesCount: 0, - } - ) + InstructionTextToken(BNInstructionTextToken { + type_: self.0.type_, + context: self.0.context, + address: self.0.address, + size: self.0.size, + operand: self.0.operand, + value: self.0.value, + width: 0, + text: self.text().to_owned().into_raw(), + confidence: 0xff, + typeNames: ptr::null_mut(), + namesCount: 0, + }) } } @@ -258,12 +281,12 @@ impl Drop for InstructionTextToken { } } +pub use binaryninjacore_sys::BNFlagRole as FlagRole; pub use binaryninjacore_sys::BNImplicitRegisterExtend as ImplicitRegisterExtend; pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition; -pub use binaryninjacore_sys::BNFlagRole as FlagRole; pub trait RegisterInfo: Sized { - type RegType: Register<InfoType=Self>; + type RegType: Register<InfoType = Self>; fn parent(&self) -> Option<Self::RegType>; fn size(&self) -> usize; @@ -271,8 +294,8 @@ pub trait RegisterInfo: Sized { fn implicit_extend(&self) -> ImplicitRegisterExtend; } -pub trait Register: Sized + Clone + Copy { - type InfoType: RegisterInfo<RegType=Self>; +pub trait Register: Sized + Clone + Copy { + type InfoType: RegisterInfo<RegType = Self>; fn name(&self) -> Cow<str>; fn info(&self) -> Self::InfoType; @@ -362,13 +385,13 @@ pub trait FlagGroup: Sized + Clone + Copy { pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { type Handle: Borrow<Self> + Clone; - type RegisterInfo: RegisterInfo<RegType=Self::Register>; - type Register: Register<InfoType=Self::RegisterInfo>; + type RegisterInfo: RegisterInfo<RegType = Self::Register>; + type Register: Register<InfoType = Self::RegisterInfo>; - type Flag: Flag<FlagClass=Self::FlagClass>; - type FlagWrite: FlagWrite<FlagType=Self::Flag, FlagClass=Self::FlagClass>; + type Flag: Flag<FlagClass = Self::FlagClass>; + type FlagWrite: FlagWrite<FlagType = Self::Flag, FlagClass = Self::FlagClass>; type FlagClass: FlagClass; - type FlagGroup: FlagGroup<FlagType=Self::Flag, FlagClass=Self::FlagClass>; + type FlagGroup: FlagGroup<FlagType = Self::Flag, FlagClass = Self::FlagClass>; type InstructionTextContainer: Into<Vec<InstructionTextToken>>; @@ -382,8 +405,17 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { fn associated_arch_by_addr(&self, addr: &mut u64) -> CoreArchitecture; fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo>; - fn instruction_text(&self, data: &[u8], addr: u64) -> Option<(usize, Self::InstructionTextContainer)>; - fn instruction_llil(&self, data: &[u8], addr: u64, il: &mut Lifter<Self>) -> Option<(usize, bool)>; + fn instruction_text( + &self, + data: &[u8], + addr: u64, + ) -> Option<(usize, Self::InstructionTextContainer)>; + fn instruction_llil( + &self, + data: &[u8], + addr: u64, + il: &mut Lifter<Self>, + ) -> Option<(usize, bool)>; /// Fallback flag value calculation path. This method is invoked when the core is unable to /// recover flag use semantics, and resorts to emitting instructions that explicitly set each @@ -394,9 +426,13 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { /// This function *MUST NOT* observe the values of other flags. /// /// This function *MUST* return `None` or an expression representing a boolean value. - fn flag_write_llil<'a>(&self, flag: Self::Flag, flag_write_type: Self::FlagWrite, op: FlagWriteOp<Self::Register>, il: &'a mut Lifter<Self>) - -> Option<LiftedExpr<'a, Self>> - { + fn flag_write_llil<'a>( + &self, + flag: Self::Flag, + flag_write_type: Self::FlagWrite, + op: FlagWriteOp<Self::Register>, + il: &'a mut Lifter<Self>, + ) -> Option<LiftedExpr<'a, Self>> { let role = flag.role(flag_write_type.class()); Some(get_default_flag_write_llil(self, role, op, il)) } @@ -406,7 +442,11 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { /// /// If automatic recovery is not possible, the `flag_cond_llil` method will be invoked to give /// this `Architecture` implementation arbitrary control over the expression to be evaluated. - fn flags_required_for_flag_condition(&self, condition: FlagCondition, class: Option<Self::FlagClass>) -> Vec<Self::Flag>; + fn flags_required_for_flag_condition( + &self, + condition: FlagCondition, + class: Option<Self::FlagClass>, + ) -> Vec<Self::Flag>; /// This function *MUST NOT* append instructions that have side effects. /// @@ -414,9 +454,12 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { /// `flags_required_for_flag_condition`. /// /// This function *MUST* return `None` or an expression representing a boolean value. - fn flag_cond_llil<'a>(&self, cond: FlagCondition, class: Option<Self::FlagClass>, il: &'a mut Lifter<Self>) - -> Option<LiftedExpr<'a, Self>> - { + fn flag_cond_llil<'a>( + &self, + cond: FlagCondition, + class: Option<Self::FlagClass>, + il: &'a mut Lifter<Self>, + ) -> Option<LiftedExpr<'a, Self>> { Some(get_default_flag_cond_llil(self, cond, class, il)) } @@ -434,7 +477,11 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { /// /// This function must not observe the values of any flag not returned by `group`'s /// `flags_required` method. - fn flag_group_llil<'a>(&self, group: Self::FlagGroup, il: &'a mut Lifter<Self>) -> Option<LiftedExpr<'a, Self>>; + fn flag_group_llil<'a>( + &self, + group: Self::FlagGroup, + il: &'a mut Lifter<Self>, + ) -> Option<LiftedExpr<'a, Self>>; fn registers_all(&self) -> Vec<Self::Register>; fn registers_full_width(&self) -> Vec<Self::Register>; @@ -446,7 +493,6 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { fn flag_classes(&self) -> Vec<Self::FlagClass>; fn flag_groups(&self) -> Vec<Self::FlagGroup>; - fn stack_pointer_reg(&self) -> Option<Self::Register>; fn link_reg(&self) -> Option<Self::Register>; @@ -540,7 +586,7 @@ impl Flag for CoreFlag { fn role(&self, class: Option<CoreFlagClass>) -> FlagRole { let class_id = match class { Some(class) => class.1, - _ => 0 + _ => 0, }; unsafe { BNGetArchitectureFlagRole(self.0, self.1, class_id) } @@ -584,10 +630,15 @@ impl FlagWrite for CoreFlagWrite { }; let ret = unsafe { - slice::from_raw_parts_mut(regs, count).iter().map(|reg| CoreFlag(self.0, *reg)).collect() + slice::from_raw_parts_mut(regs, count) + .iter() + .map(|reg| CoreFlag(self.0, *reg)) + .collect() }; - unsafe { BNFreeRegisterList(regs); } + unsafe { + BNFreeRegisterList(regs); + } ret } @@ -659,10 +710,15 @@ impl FlagGroup for CoreFlagGroup { }; let ret = unsafe { - slice::from_raw_parts_mut(regs, count).iter().map(|reg| CoreFlag(self.0, *reg)).collect() + slice::from_raw_parts_mut(regs, count) + .iter() + .map(|reg| CoreFlag(self.0, *reg)) + .collect() }; - unsafe { BNFreeRegisterList(regs); } + unsafe { + BNFreeRegisterList(regs); + } ret } @@ -671,11 +727,21 @@ impl FlagGroup for CoreFlagGroup { let mut count: usize = 0; unsafe { - let flag_conds = BNGetArchitectureFlagConditionsForSemanticFlagGroup(self.0, self.1, &mut count as *mut _); + let flag_conds = BNGetArchitectureFlagConditionsForSemanticFlagGroup( + self.0, + self.1, + &mut count as *mut _, + ); - let ret = slice::from_raw_parts_mut(flag_conds, count).iter().map(|class_cond| { - (CoreFlagClass(self.0, class_cond.semanticClass), class_cond.condition) - }).collect(); + let ret = slice::from_raw_parts_mut(flag_conds, count) + .iter() + .map(|class_cond| { + ( + CoreFlagClass(self.0, class_cond.semanticClass), + class_cond.condition, + ) + }) + .collect(); BNFreeFlagConditionsForSemanticFlagGroup(flag_conds); @@ -695,7 +761,9 @@ impl ops::Deref for CoreArchitectureList { impl Drop for CoreArchitectureList { fn drop(&mut self) { - unsafe { BNFreeArchitectureList(self.0); } + unsafe { + BNFreeArchitectureList(self.0); + } } } @@ -754,9 +822,7 @@ impl CoreArchitecture { } pub fn name(&self) -> BnString { - unsafe { - BnString::from_raw(BNGetArchitectureName(self.0)) - } + unsafe { BnString::from_raw(BNGetArchitectureName(self.0)) } } } @@ -810,7 +876,15 @@ impl Architecture for CoreArchitecture { fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo> { let mut info = unsafe { zeroed::<InstructionInfo>() }; - let success = unsafe { BNGetInstructionInfo(self.0, data.as_ptr(), addr, data.len(), &mut (info.0) as *mut _) }; + let success = unsafe { + BNGetInstructionInfo( + self.0, + data.as_ptr(), + addr, + data.len(), + &mut (info.0) as *mut _, + ) + }; if success { Some(info) @@ -819,14 +893,24 @@ impl Architecture for CoreArchitecture { } } - fn instruction_text(&self, data: &[u8], addr: u64) -> Option<(usize, InstructionTextTokenList)> { + fn instruction_text( + &self, + data: &[u8], + addr: u64, + ) -> Option<(usize, InstructionTextTokenList)> { let mut consumed = data.len(); let mut count: usize = 0; let mut result: *mut BNInstructionTextToken = ptr::null_mut(); unsafe { - if BNGetInstructionText(self.0, data.as_ptr(), addr, &mut consumed as *mut _, &mut result as *mut _, - &mut count as *mut _) { + if BNGetInstructionText( + self.0, + data.as_ptr(), + addr, + &mut consumed as *mut _, + &mut result as *mut _, + &mut count as *mut _, + ) { Some((consumed, InstructionTextTokenList(result, count))) } else { None @@ -834,29 +918,42 @@ impl Architecture for CoreArchitecture { } } - fn instruction_llil(&self, _data: &[u8], _addr: u64, _il: &mut Lifter<Self>) -> Option<(usize, bool)> { + fn instruction_llil( + &self, + _data: &[u8], + _addr: u64, + _il: &mut Lifter<Self>, + ) -> Option<(usize, bool)> { None } - fn flag_write_llil<'a>(&self, _flag: Self::Flag, _flag_write: Self::FlagWrite, _op: FlagWriteOp<Self::Register>, _il: &'a mut Lifter<Self>) - -> Option<LiftedExpr<'a, Self>> - { + fn flag_write_llil<'a>( + &self, + _flag: Self::Flag, + _flag_write: Self::FlagWrite, + _op: FlagWriteOp<Self::Register>, + _il: &'a mut Lifter<Self>, + ) -> Option<LiftedExpr<'a, Self>> { None } - fn flag_cond_llil<'a>(&self, _cond: FlagCondition, _class: Option<Self::FlagClass>, _il: &'a mut Lifter<Self>) - -> Option<LiftedExpr<'a, Self>> - { + fn flag_cond_llil<'a>( + &self, + _cond: FlagCondition, + _class: Option<Self::FlagClass>, + _il: &'a mut Lifter<Self>, + ) -> Option<LiftedExpr<'a, Self>> { None } - fn flag_group_llil<'a>(&self, _group: Self::FlagGroup, _il: &'a mut Lifter<Self>) - -> Option<LiftedExpr<'a, Self>> - { + fn flag_group_llil<'a>( + &self, + _group: Self::FlagGroup, + _il: &'a mut Lifter<Self>, + ) -> Option<LiftedExpr<'a, Self>> { None } - fn registers_all(&self) -> Vec<CoreRegister> { unsafe { let mut count: usize = 0; @@ -985,12 +1082,21 @@ impl Architecture for CoreArchitecture { } } - fn flags_required_for_flag_condition(&self, condition: FlagCondition, class: Option<Self::FlagClass>) -> Vec<Self::Flag> { + fn flags_required_for_flag_condition( + &self, + condition: FlagCondition, + class: Option<Self::FlagClass>, + ) -> Vec<Self::Flag> { let class_id = class.map(|c| c.id()).unwrap_or(0); unsafe { let mut count: usize = 0; - let flags = BNGetArchitectureFlagsRequiredForFlagCondition(self.0, condition, class_id, &mut count as *mut _); + let flags = BNGetArchitectureFlagsRequiredForFlagCondition( + self.0, + condition, + class_id, + &mut count as *mut _, + ); let ret = slice::from_raw_parts_mut(flags, count) .iter() @@ -1006,14 +1112,14 @@ impl Architecture for CoreArchitecture { fn stack_pointer_reg(&self) -> Option<CoreRegister> { match unsafe { BNGetArchitectureStackPointerRegister(self.0) } { 0xffff_ffff => None, - reg => Some(CoreRegister(self.0, reg)) + reg => Some(CoreRegister(self.0, reg)), } } fn link_reg(&self) -> Option<CoreRegister> { match unsafe { BNGetArchitectureLinkRegister(self.0) } { 0xffff_ffff => None, - reg => Some(CoreRegister(self.0, reg)) + reg => Some(CoreRegister(self.0, reg)), } } @@ -1066,13 +1172,16 @@ macro_rules! cc_func { fn $set_name(&self, cc: &CallingConvention<Self>) { let handle = self.as_ref(); - assert!(cc.arch_handle.borrow().as_ref().0 == handle.0, "use of calling convention with non-matching architecture!"); + assert!( + cc.arch_handle.borrow().as_ref().0 == handle.0, + "use of calling convention with non-matching architecture!" + ); unsafe { $set_api(handle.0, cc.handle); } } - } + }; } /// Contains helper methods for all types implementing 'Architecture' @@ -1080,23 +1189,41 @@ pub trait ArchitectureExt: Architecture { fn register_by_name<S: BnStrCompatible>(&self, name: S) -> Option<Self::Register> { let name = name.as_bytes_with_nul(); - match unsafe { BNGetArchitectureRegisterByName(self.as_ref().0, name.as_ref().as_ptr() as *mut _) } { + match unsafe { + BNGetArchitectureRegisterByName(self.as_ref().0, name.as_ref().as_ptr() as *mut _) + } { 0xffff_ffff => None, - reg => self.register_from_id(reg) + reg => self.register_from_id(reg), } } - cc_func!(get_default_calling_convention, BNGetArchitectureDefaultCallingConvention, - set_default_calling_convention, BNSetArchitectureDefaultCallingConvention); + cc_func!( + get_default_calling_convention, + BNGetArchitectureDefaultCallingConvention, + set_default_calling_convention, + BNSetArchitectureDefaultCallingConvention + ); - cc_func!(get_cdecl_calling_convention, BNGetArchitectureCdeclCallingConvention, - set_cdecl_calling_convention, BNSetArchitectureCdeclCallingConvention); + cc_func!( + get_cdecl_calling_convention, + BNGetArchitectureCdeclCallingConvention, + set_cdecl_calling_convention, + BNSetArchitectureCdeclCallingConvention + ); - cc_func!(get_stdcall_calling_convention, BNGetArchitectureStdcallCallingConvention, - set_stdcall_calling_convention, BNSetArchitectureStdcallCallingConvention); + cc_func!( + get_stdcall_calling_convention, + BNGetArchitectureStdcallCallingConvention, + set_stdcall_calling_convention, + BNSetArchitectureStdcallCallingConvention + ); - cc_func!(get_fastcall_calling_convention, BNGetArchitectureFastcallCallingConvention, - set_fastcall_calling_convention, BNSetArchitectureFastcallCallingConvention); + cc_func!( + get_fastcall_calling_convention, + BNGetArchitectureFastcallCallingConvention, + set_fastcall_calling_convention, + BNSetArchitectureFastcallCallingConvention + ); fn standalone_platform(&self) -> Option<Ref<Platform>> { unsafe { @@ -1111,21 +1238,21 @@ pub trait ArchitectureExt: Architecture { } } -impl<T: Architecture> ArchitectureExt for T { } +impl<T: Architecture> ArchitectureExt for T {} pub fn register_architecture<S, A, F>(name: S, func: F) -> &'static A where S: BnStrCompatible, - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync + Sized, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync + Sized, F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A, { - use std::os::raw::{c_void, c_char}; use std::mem; + use std::os::raw::{c_char, c_void}; #[repr(C)] struct ArchitectureBuilder<A, F> where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A, { arch: A, @@ -1134,23 +1261,26 @@ where extern "C" fn cb_init<A, F>(ctxt: *mut c_void, obj: *mut BNArchitecture) where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A, { unsafe { let custom_arch = &mut *(ctxt as *mut ArchitectureBuilder<A, F>); let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A + handle: ctxt as *mut A, }; let create = ptr::read(&custom_arch.func); - ptr::write(&mut custom_arch.arch, create(custom_arch_handle, CoreArchitecture(obj))); + ptr::write( + &mut custom_arch.arch, + create(custom_arch_handle, CoreArchitecture(obj)), + ); } } extern "C" fn cb_endianness<A>(ctxt: *mut c_void) -> BNEndianness where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; custom_arch.endianness() @@ -1158,7 +1288,7 @@ where extern "C" fn cb_address_size<A>(ctxt: *mut c_void) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; custom_arch.address_size() @@ -1166,7 +1296,7 @@ where extern "C" fn cb_default_integer_size<A>(ctxt: *mut c_void) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; custom_arch.default_integer_size() @@ -1174,7 +1304,7 @@ where extern "C" fn cb_instruction_alignment<A>(ctxt: *mut c_void) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; custom_arch.instruction_alignment() @@ -1182,7 +1312,7 @@ where extern "C" fn cb_max_instr_len<A>(ctxt: *mut c_void) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; custom_arch.max_instr_len() @@ -1190,15 +1320,18 @@ where extern "C" fn cb_opcode_display_len<A>(ctxt: *mut c_void) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; custom_arch.opcode_display_len() } - extern "C" fn cb_associated_arch_by_addr<A>(ctxt: *mut c_void, addr: *mut u64) -> *mut BNArchitecture + extern "C" fn cb_associated_arch_by_addr<A>( + ctxt: *mut c_void, + addr: *mut u64, + ) -> *mut BNArchitecture where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let addr = unsafe { &mut *(addr) }; @@ -1206,10 +1339,15 @@ where custom_arch.associated_arch_by_addr(addr).0 } - extern "C" fn cb_instruction_info<A>(ctxt: *mut c_void, data: *const u8, addr: u64, - len: usize, result: *mut BNInstructionInfo) -> bool + extern "C" fn cb_instruction_info<A>( + ctxt: *mut c_void, + data: *const u8, + addr: u64, + len: usize, + result: *mut BNInstructionInfo, + ) -> bool where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let data = unsafe { slice::from_raw_parts(data, len) }; @@ -1224,10 +1362,16 @@ where } } - extern "C" fn cb_get_instruction_text<A>(ctxt: *mut c_void, data: *const u8, addr: u64, len: *mut usize, - result: *mut *mut BNInstructionTextToken, count: *mut usize) -> bool + extern "C" fn cb_get_instruction_text<A>( + ctxt: *mut c_void, + data: *const u8, + addr: u64, + len: *mut usize, + result: *mut *mut BNInstructionTextToken, + count: *mut usize, + ) -> bool where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let data = unsafe { slice::from_raw_parts(data, *len) }; @@ -1253,17 +1397,23 @@ where } extern "C" fn cb_free_instruction_text(tokens: *mut BNInstructionTextToken, count: usize) { - let _tokens = unsafe { Vec::from_raw_parts(tokens as *mut InstructionTextToken, count, count) }; + let _tokens = + unsafe { Vec::from_raw_parts(tokens as *mut InstructionTextToken, count, count) }; } - extern "C" fn cb_instruction_llil<A>(ctxt: *mut c_void, data: *const u8, addr: u64, len: *mut usize, - il: *mut BNLowLevelILFunction) -> bool + extern "C" fn cb_instruction_llil<A>( + ctxt: *mut c_void, + data: *const u8, + addr: u64, + len: *mut usize, + il: *mut BNLowLevelILFunction, + ) -> bool where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A + handle: ctxt as *mut A, }; let data = unsafe { slice::from_raw_parts(data, *len) }; @@ -1280,7 +1430,7 @@ where extern "C" fn cb_reg_name<A>(ctxt: *mut c_void, reg: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1292,7 +1442,7 @@ where extern "C" fn cb_flag_name<A>(ctxt: *mut c_void, flag: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1304,7 +1454,7 @@ where extern "C" fn cb_flag_write_name<A>(ctxt: *mut c_void, flag_write: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1316,7 +1466,7 @@ where extern "C" fn cb_semantic_flag_class_name<A>(ctxt: *mut c_void, class: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1328,7 +1478,7 @@ where extern "C" fn cb_semantic_flag_group_name<A>(ctxt: *mut c_void, group: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1338,7 +1488,10 @@ where } } - fn alloc_register_list<I: Iterator<Item=u32> + ExactSizeIterator>(items: I, count: &mut usize) -> *mut u32 { + fn alloc_register_list<I: Iterator<Item = u32> + ExactSizeIterator>( + items: I, + count: &mut usize, + ) -> *mut u32 { let len = items.len(); *count = len; @@ -1364,7 +1517,7 @@ where extern "C" fn cb_registers_full_width<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let regs = custom_arch.registers_full_width(); @@ -1374,7 +1527,7 @@ where extern "C" fn cb_registers_all<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let regs = custom_arch.registers_all(); @@ -1384,7 +1537,7 @@ where extern "C" fn cb_registers_global<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let regs = custom_arch.registers_global(); @@ -1394,7 +1547,7 @@ where extern "C" fn cb_registers_system<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let regs = custom_arch.registers_system(); @@ -1404,7 +1557,7 @@ where extern "C" fn cb_flags<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let flags = custom_arch.flags(); @@ -1414,7 +1567,7 @@ where extern "C" fn cb_flag_write_types<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let flag_writes = custom_arch.flag_write_types(); @@ -1424,7 +1577,7 @@ where extern "C" fn cb_semantic_flag_classes<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let flag_classes = custom_arch.flag_classes(); @@ -1434,7 +1587,7 @@ where extern "C" fn cb_semantic_flag_groups<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let flag_groups = custom_arch.flag_groups(); @@ -1444,21 +1597,28 @@ where extern "C" fn cb_flag_role<A>(ctxt: *mut c_void, flag: u32, class: u32) -> BNFlagRole where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - if let (Some(flag), class) = (custom_arch.flag_from_id(flag), custom_arch.flag_class_from_id(class)) { + if let (Some(flag), class) = ( + custom_arch.flag_from_id(flag), + custom_arch.flag_class_from_id(class), + ) { flag.role(class) } else { FlagRole::SpecialFlagRole } } - extern "C" fn cb_flags_required_for_flag_cond<A>(ctxt: *mut c_void, cond: BNLowLevelILFlagCondition, class: u32, - count: *mut usize) -> *mut u32 + extern "C" fn cb_flags_required_for_flag_cond<A>( + ctxt: *mut c_void, + cond: BNLowLevelILFlagCondition, + class: u32, + count: *mut usize, + ) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let class = custom_arch.flag_class_from_id(class); @@ -1467,9 +1627,13 @@ where alloc_register_list(flags.iter().map(|r| r.id()), unsafe { &mut *count }) } - extern "C" fn cb_flags_required_for_semantic_flag_group<A>(ctxt: *mut c_void, group: u32, count: *mut usize) -> *mut u32 + extern "C" fn cb_flags_required_for_semantic_flag_group<A>( + ctxt: *mut c_void, + group: u32, + count: *mut usize, + ) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1477,15 +1641,20 @@ where let flags = group.flags_required(); alloc_register_list(flags.iter().map(|r| r.id()), unsafe { &mut *count }) } else { - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } } - extern "C" fn cb_flag_conditions_for_semantic_flag_group<A>(ctxt: *mut c_void, group: u32, count: *mut usize) - -> *mut BNFlagConditionForSemanticClass + extern "C" fn cb_flag_conditions_for_semantic_flag_group<A>( + ctxt: *mut c_void, + group: u32, + count: *mut usize, + ) -> *mut BNFlagConditionForSemanticClass where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1493,7 +1662,8 @@ where let flag_conditions = group.flag_conditions(); unsafe { - let allocation_size = mem::size_of::<BNFlagConditionForSemanticClass>() * flag_conditions.len(); + let allocation_size = + mem::size_of::<BNFlagConditionForSemanticClass>() * flag_conditions.len(); let result = libc::malloc(allocation_size) as *mut BNFlagConditionForSemanticClass; let out_slice = slice::from_raw_parts_mut(result, flag_conditions.len()); @@ -1508,21 +1678,31 @@ where result } } else { - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } } - extern "C" fn cb_free_flag_conditions_for_semantic_flag_group<A>(_ctxt: *mut c_void, conds: *mut BNFlagConditionForSemanticClass) - where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + extern "C" fn cb_free_flag_conditions_for_semantic_flag_group<A>( + _ctxt: *mut c_void, + conds: *mut BNFlagConditionForSemanticClass, + ) where + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { - unsafe { libc::free(conds as *mut _); } + unsafe { + libc::free(conds as *mut _); + } } - extern "C" fn cb_flags_written_by_write_type<A>(ctxt: *mut c_void, write_type: u32, count: *mut usize) -> *mut u32 + extern "C" fn cb_flags_written_by_write_type<A>( + ctxt: *mut c_void, + write_type: u32, + count: *mut usize, + ) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1530,28 +1710,43 @@ where let written = write_type.flags_written(); alloc_register_list(written.iter().map(|f| f.id()), unsafe { &mut *count }) } else { - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } } - extern "C" fn cb_semantic_class_for_flag_write_type<A>(ctxt: *mut c_void, write_type: u32) -> u32 + extern "C" fn cb_semantic_class_for_flag_write_type<A>( + ctxt: *mut c_void, + write_type: u32, + ) -> u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - custom_arch.flag_write_from_id(write_type).map(|w| w.id()).unwrap_or(0) + custom_arch + .flag_write_from_id(write_type) + .map(|w| w.id()) + .unwrap_or(0) } - extern "C" fn cb_flag_write_llil<A>(ctxt: *mut c_void, op: BNLowLevelILOperation, size: usize, flag_write: u32, - flag: u32, operands_raw: *mut BNRegisterOrConstant, operand_count: usize, - il: *mut BNLowLevelILFunction) -> usize + extern "C" fn cb_flag_write_llil<A>( + ctxt: *mut c_void, + op: BNLowLevelILOperation, + size: usize, + flag_write: u32, + flag: u32, + operands_raw: *mut BNRegisterOrConstant, + operand_count: usize, + il: *mut BNLowLevelILFunction, + ) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A + handle: ctxt as *mut A, }; let flag_write = custom_arch.flag_write_from_id(flag_write); @@ -1566,14 +1761,25 @@ where return expr.expr_idx; } } else { - warn!("unable to unpack flag write op: {:?} with {} operands", op, operands.len()); + warn!( + "unable to unpack flag write op: {:?} with {} operands", + op, + operands.len() + ); } let role = flag.role(flag_write.class()); unsafe { - BNGetDefaultArchitectureFlagWriteLowLevelIL(custom_arch.as_ref().0, op, size, - role, operands_raw, operand_count, il) + BNGetDefaultArchitectureFlagWriteLowLevelIL( + custom_arch.as_ref().0, + op, + size, + role, + operands_raw, + operand_count, + il, + ) } } else { // TODO this should be impossible; requires bad flag/flag_write ids passed in; @@ -1582,14 +1788,18 @@ where } } - extern "C" fn cb_flag_cond_llil<A>(ctxt: *mut c_void, cond: FlagCondition, class: u32, - il: *mut BNLowLevelILFunction) -> usize + extern "C" fn cb_flag_cond_llil<A>( + ctxt: *mut c_void, + cond: FlagCondition, + class: u32, + il: *mut BNLowLevelILFunction, + ) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A + handle: ctxt as *mut A, }; let class = custom_arch.flag_class_from_id(class); @@ -1603,14 +1813,17 @@ where lifter.unimplemented().expr_idx } - extern "C" fn cb_flag_group_llil<A>(ctxt: *mut c_void, group: u32, - il: *mut BNLowLevelILFunction) -> usize + extern "C" fn cb_flag_group_llil<A>( + ctxt: *mut c_void, + group: u32, + il: *mut BNLowLevelILFunction, + ) -> usize where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A + handle: ctxt as *mut A, }; let mut lifter = unsafe { Lifter::from_raw(custom_arch_handle, il) }; @@ -1639,7 +1852,7 @@ where extern "C" fn cb_register_info<A>(ctxt: *mut c_void, reg: u32, result: *mut BNRegisterInfo) where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; let result = unsafe { &mut *result }; @@ -1660,7 +1873,7 @@ where extern "C" fn cb_stack_pointer<A>(ctxt: *mut c_void) -> u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1673,7 +1886,7 @@ where extern "C" fn cb_link_reg<A>(ctxt: *mut c_void) -> u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; @@ -1686,7 +1899,7 @@ where extern "C" fn cb_reg_stack_name<A>(ctxt: *mut c_void, _stack: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; BnString::new("reg_stack").into_raw() @@ -1694,24 +1907,29 @@ where extern "C" fn cb_reg_stacks<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } - extern "C" fn cb_reg_stack_info<A>(ctxt: *mut c_void, _stack: u32, _info: *mut BNRegisterStackInfo) - where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + extern "C" fn cb_reg_stack_info<A>( + ctxt: *mut c_void, + _stack: u32, + _info: *mut BNRegisterStackInfo, + ) where + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; } extern "C" fn cb_intrinsic_name<A>(ctxt: *mut c_void, _intrinsic: u32) -> *mut c_char where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; BnString::new("intrinsic").into_raw() @@ -1719,71 +1937,118 @@ where extern "C" fn cb_intrinsics<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } - extern "C" fn cb_intrinsic_inputs<A>(ctxt: *mut c_void, _intrinsic: u32, count: *mut usize) -> *mut BNNameAndType + extern "C" fn cb_intrinsic_inputs<A>( + ctxt: *mut c_void, + _intrinsic: u32, + count: *mut usize, + ) -> *mut BNNameAndType where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } - extern "C" fn cb_free_name_and_types<A>(ctxt: *mut c_void, _nt: *mut BNNameAndType, _count: usize) - where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + extern "C" fn cb_free_name_and_types<A>( + ctxt: *mut c_void, + _nt: *mut BNNameAndType, + _count: usize, + ) where + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; } - extern "C" fn cb_intrinsic_outputs<A>(ctxt: *mut c_void, _intrinsic: u32, count: *mut usize) -> *mut BNTypeWithConfidence + extern "C" fn cb_intrinsic_outputs<A>( + ctxt: *mut c_void, + _intrinsic: u32, + count: *mut usize, + ) -> *mut BNTypeWithConfidence where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; - unsafe { *count = 0; } + unsafe { + *count = 0; + } ptr::null_mut() } - extern "C" fn cb_free_type_list<A>(ctxt: *mut c_void, _tl: *mut BNTypeWithConfidence, _count: usize) - where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync, + extern "C" fn cb_free_type_list<A>( + ctxt: *mut c_void, + _tl: *mut BNTypeWithConfidence, + _count: usize, + ) where + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { let _custom_arch = unsafe { &*(ctxt as *mut A) }; } - extern "C" fn cb_assemble(_ctxt: *mut c_void, _code: *const c_char, _addr: u64, - _result: *mut BNDataBuffer, errors: *mut *mut c_char) -> bool - { - unsafe { *errors = ptr::null_mut(); } + // TODO : I have no idea what I'm doing and this is likely wrong! + extern "C" fn cb_can_assemble(_ctxt: *mut c_void) -> bool { false } - extern "C" fn cb_patch_unavailable(_ctxt: *mut c_void, _data: *const u8, _addr: u64, _len: usize) -> bool { + extern "C" fn cb_assemble( + _ctxt: *mut c_void, + _code: *const c_char, + _addr: u64, + _result: *mut BNDataBuffer, + errors: *mut *mut c_char, + ) -> bool { + unsafe { + *errors = ptr::null_mut(); + } false } - extern "C" fn cb_do_patch_unavailable(_ctxt: *mut c_void, _data: *mut u8, _addr: u64, _len: usize) -> bool { + extern "C" fn cb_patch_unavailable( + _ctxt: *mut c_void, + _data: *const u8, + _addr: u64, + _len: usize, + ) -> bool { false } - extern "C" fn cb_skip_patch_unavailable(_ctxt: *mut c_void, _data: *mut u8, _addr: u64, _len: usize, _val: u64) -> bool { + extern "C" fn cb_do_patch_unavailable( + _ctxt: *mut c_void, + _data: *mut u8, + _addr: u64, + _len: usize, + ) -> bool { + false + } + + extern "C" fn cb_skip_patch_unavailable( + _ctxt: *mut c_void, + _data: *mut u8, + _addr: u64, + _len: usize, + _val: u64, + ) -> bool { false } let name = name.as_bytes_with_nul(); let uninit_arch = ArchitectureBuilder { - arch: unsafe { mem::uninitialized() }, + arch: unsafe { zeroed() }, func: func, }; @@ -1820,8 +2085,12 @@ where getFlagsRequiredForFlagCondition: Some(cb_flags_required_for_flag_cond::<A>), getFlagsRequiredForSemanticFlagGroup: Some(cb_flags_required_for_semantic_flag_group::<A>), - getFlagConditionsForSemanticFlagGroup: Some(cb_flag_conditions_for_semantic_flag_group::<A>), - freeFlagConditionsForSemanticFlagGroup: Some(cb_free_flag_conditions_for_semantic_flag_group::<A>), + getFlagConditionsForSemanticFlagGroup: Some( + cb_flag_conditions_for_semantic_flag_group::<A>, + ), + freeFlagConditionsForSemanticFlagGroup: Some( + cb_free_flag_conditions_for_semantic_flag_group::<A>, + ), getFlagsWrittenByFlagWriteType: Some(cb_flags_written_by_write_type::<A>), getSemanticClassForFlagWriteType: Some(cb_semantic_class_for_flag_write_type::<A>), @@ -1848,6 +2117,7 @@ where getIntrinsicOutputs: Some(cb_intrinsic_outputs::<A>), freeTypeList: Some(cb_free_type_list::<A>), + canAssemble: Some(cb_can_assemble), assemble: Some(cb_assemble), isNeverBranchPatchAvailable: Some(cb_patch_unavailable), @@ -1863,7 +2133,8 @@ where }; unsafe { - let res = BNRegisterArchitecture(name.as_ref().as_ptr() as *mut _, &mut custom_arch as *mut _); + let res = + BNRegisterArchitecture(name.as_ref().as_ptr() as *mut _, &mut custom_arch as *mut _); assert!(!res.is_null()); @@ -1873,39 +2144,40 @@ where pub struct CustomArchitectureHandle<A> where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync, { - handle: *mut A + handle: *mut A, } -unsafe impl<A> Send for CustomArchitectureHandle<A> -where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync -{} +unsafe impl<A> Send for CustomArchitectureHandle<A> where + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync +{ +} -unsafe impl<A> Sync for CustomArchitectureHandle<A> -where - A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync -{} +unsafe impl<A> Sync for CustomArchitectureHandle<A> where + A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync +{ +} impl<A> Clone for CustomArchitectureHandle<A> where - A: 'static + Architecture<Handle=Self> + Send + Sync + A: 'static + Architecture<Handle = Self> + Send + Sync, { fn clone(&self) -> Self { - Self { handle: self.handle } + Self { + handle: self.handle, + } } } -impl<A> Copy for CustomArchitectureHandle<A> -where - A: 'static + Architecture<Handle=Self> + Send + Sync +impl<A> Copy for CustomArchitectureHandle<A> where + A: 'static + Architecture<Handle = Self> + Send + Sync { } impl<A> Borrow<A> for CustomArchitectureHandle<A> where - A: 'static + Architecture<Handle=Self> + Send + Sync + A: 'static + Architecture<Handle = Self> + Send + Sync, { fn borrow(&self) -> &A { unsafe { &*self.handle } diff --git a/rust/src/basicblock.rs b/rust/src/basicblock.rs index db7989a0..6b493803 100644 --- a/rust/src/basicblock.rs +++ b/rust/src/basicblock.rs @@ -1,8 +1,22 @@ +// Copyright 2021 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; -use binaryninjacore_sys::*; use crate::architecture::CoreArchitecture; use crate::function::Function; +use binaryninjacore_sys::*; use crate::rc::*; @@ -38,7 +52,11 @@ impl<'a, C: 'a + BlockContext> Edge<'a, C> { impl<'a, C: 'a + fmt::Debug + BlockContext> fmt::Debug for Edge<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?} ({}) {:?} -> {:?}", self.branch, self.back_edge, &*self.source, &*self.target) + write!( + f, + "{:?} ({}) {:?} -> {:?}", + self.branch, self.back_edge, &*self.source, &*self.target + ) } } @@ -60,8 +78,17 @@ unsafe impl<'a, C: 'a + BlockContext> CoreOwnedArrayWrapper<'a> for Edge<'a, C> type Wrapped = Edge<'a, C>; unsafe fn wrap_raw(raw: &'a BNBasicBlockEdge, context: &'a Self::Context) -> Edge<'a, C> { - let edge_target = Guard::new(BasicBlock::from_raw(raw.target, context.orig_block.context.clone()), raw); - let orig_block = Guard::new(BasicBlock::from_raw(context.orig_block.handle, context.orig_block.context.clone()), raw); + let edge_target = Guard::new( + BasicBlock::from_raw(raw.target, context.orig_block.context.clone()), + raw, + ); + let orig_block = Guard::new( + BasicBlock::from_raw( + context.orig_block.handle, + context.orig_block.context.clone(), + ), + raw, + ); let (source, target) = match context.dir { EdgeDirection::Incoming => (edge_target, orig_block), @@ -79,7 +106,7 @@ unsafe impl<'a, C: 'a + BlockContext> CoreOwnedArrayWrapper<'a> for Edge<'a, C> pub trait BlockContext: Clone + Sync + Send + Sized { type Instruction; - type Iter: Iterator<Item=Self::Instruction>; + type Iter: Iterator<Item = Self::Instruction>; fn start(&self, block: &BasicBlock<Self>) -> Self::Instruction; fn iter(&self, block: &BasicBlock<Self>) -> Self::Iter; @@ -135,10 +162,14 @@ impl<C: BlockContext> BasicBlock<C> { let mut count = 0; let edges = BNGetBasicBlockIncomingEdges(self.handle, &mut count); - Array::new(edges, count, EdgeContext { - dir: EdgeDirection::Incoming, - orig_block: self, - }) + Array::new( + edges, + count, + EdgeContext { + dir: EdgeDirection::Incoming, + orig_block: self, + }, + ) } } @@ -147,10 +178,14 @@ impl<C: BlockContext> BasicBlock<C> { let mut count = 0; let edges = BNGetBasicBlockOutgoingEdges(self.handle, &mut count); - Array::new(edges, count, EdgeContext { - dir: EdgeDirection::Outgoing, - orig_block: self, - }) + Array::new( + edges, + count, + EdgeContext { + dir: EdgeDirection::Outgoing, + orig_block: self, + }, + ) } } @@ -216,7 +251,6 @@ impl<C: BlockContext> BasicBlock<C> { } // TODO iterated dominance frontier - } impl<'a, C: BlockContext> IntoIterator for &'a BasicBlock<C> { @@ -230,7 +264,14 @@ impl<'a, C: BlockContext> IntoIterator for &'a BasicBlock<C> { impl<C: fmt::Debug + BlockContext> fmt::Debug for BasicBlock<C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "<bb handle {:p} context {:?} contents: {} -> {}>", self.handle, &self.context, self.raw_start(), self.raw_end()) + write!( + f, + "<bb handle {:p} context {:?} contents: {} -> {}>", + self.handle, + &self.context, + self.raw_start(), + self.raw_end() + ) } } @@ -271,4 +312,3 @@ unsafe impl<'a, C: 'a + BlockContext> CoreOwnedArrayWrapper<'a> for BasicBlock<C Guard::new(BasicBlock::from_raw(*raw, context.clone()), context) } } - diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs index b6d1d1a7..a011b9e0 100644 --- a/rust/src/binaryview.rs +++ b/rust/src/binaryview.rs @@ -1,45 +1,60 @@ +// Copyright 2021 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::*; pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; -use std::result; -use std::slice; use std::ops; -use std::marker::PhantomData; - -use std::os::raw::{c_void, c_char}; -use std::mem; use std::ptr; - -use crate::Endianness; +use std::result; use crate::architecture::Architecture; use crate::architecture::CoreArchitecture; -use crate::platform::Platform; -use crate::filemetadata::FileMetadata; +use crate::basicblock::BasicBlock; +use crate::databuffer::DataBuffer; use crate::fileaccessor::FileAccessor; -use crate::symbol::{SymType, Symbol}; -use crate::segment::{Segment, SegmentBuilder}; -use crate::section::{Section, SectionBuilder}; +use crate::filemetadata::FileMetadata; +use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; -use crate::basicblock::BasicBlock; -use crate::types::Type; -use crate::settings::Settings; +use crate::platform::Platform; +use crate::section::{Section, SectionBuilder}; +use crate::segment::{Segment, SegmentBuilder}; +use crate::symbol::{Symbol, SymbolType}; +use crate::types::{QualifiedName, Type}; +use crate::Endianness; -use crate::string::*; use crate::rc::*; +use crate::string::*; -// TODO -// merge filemetadata/fileaccessor under here? -// general reorg of modules related to bv +// TODO : general reorg of modules related to bv pub type Result<R> = result::Result<R, ()>; pub trait BinaryViewBase: AsRef<BinaryView> { - fn read(&self, _buf: &mut [u8], _offset: u64) -> usize { 0 } - fn write(&self, _offset: u64, _data: &[u8]) -> usize { 0 } - fn insert(&self, _offset: u64, _data: &[u8]) -> usize { 0 } - fn remove(&self, _offset: u64, _len: usize) -> usize { 0 } + fn read(&self, _buf: &mut [u8], _offset: u64) -> usize { + 0 + } + fn write(&self, _offset: u64, _data: &[u8]) -> usize { + 0 + } + fn insert(&self, _offset: u64, _data: &[u8]) -> usize { + 0 + } + fn remove(&self, _offset: u64, _len: usize) -> usize { + 0 + } fn offset_valid(&self, offset: u64) -> bool { let mut buf = [0u8; 1]; @@ -80,11 +95,19 @@ pub trait BinaryViewBase: AsRef<BinaryView> { ModificationStatus::Original } - fn start(&self) -> u64 { 0 } - fn len(&self) -> usize { 0 } + fn start(&self) -> u64 { + 0 + } + fn len(&self) -> usize { + 0 + } - fn executable(&self) -> bool { true } - fn relocatable(&self) -> bool { true } + fn executable(&self) -> bool { + true + } + fn relocatable(&self) -> bool { + true + } fn entry_point(&self) -> u64; fn default_endianness(&self) -> Endianness; @@ -126,7 +149,7 @@ pub trait BinaryViewExt: BinaryViewBase { let res; { - let dest_slice = ret.get_unchecked_mut(0 .. len); + let dest_slice = ret.get_unchecked_mut(0..len); res = self.read(dest_slice, offset); } @@ -149,7 +172,7 @@ pub trait BinaryViewExt: BinaryViewBase { let res; { - let dest_slice = dest.get_unchecked_mut(starting_len .. starting_len + len); + let dest_slice = dest.get_unchecked_mut(starting_len..starting_len + len); res = self.read(dest_slice, offset); } @@ -162,15 +185,21 @@ pub trait BinaryViewExt: BinaryViewBase { } fn notify_data_written(&self, offset: u64, len: usize) { - unsafe { BNNotifyDataWritten(self.as_ref().handle, offset, len); } + unsafe { + BNNotifyDataWritten(self.as_ref().handle, offset, len); + } } fn notify_data_inserted(&self, offset: u64, len: usize) { - unsafe { BNNotifyDataInserted(self.as_ref().handle, offset, len); } + unsafe { + BNNotifyDataInserted(self.as_ref().handle, offset, len); + } } fn notify_data_removed(&self, offset: u64, len: usize) { - unsafe { BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64); } + unsafe { + BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64); + } } fn offset_has_code_semantics(&self, offset: u64) -> bool { @@ -186,7 +215,9 @@ pub trait BinaryViewExt: BinaryViewBase { } fn update_analysis_and_wait(&self) { - unsafe { BNUpdateAnalysisAndWait(self.as_ref().handle); } + unsafe { + BNUpdateAnalysisAndWait(self.as_ref().handle); + } } fn default_arch(&self) -> Option<CoreArchitecture> { @@ -253,7 +284,11 @@ pub trait BinaryViewExt: BinaryViewBase { let raw_name = raw_name.as_bytes_with_nul(); unsafe { - let raw_sym = BNGetSymbolByRawName(self.as_ref().handle, raw_name.as_ref().as_ptr() as *mut _, ptr::null_mut()); + let raw_sym = BNGetSymbolByRawName( + self.as_ref().handle, + raw_name.as_ref().as_ptr() as *mut _, + ptr::null_mut(), + ); if raw_sym.is_null() { return Err(()); @@ -277,7 +312,12 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { let mut count = 0; - let handles = BNGetSymbolsByName(self.as_ref().handle, raw_name.as_ref().as_ptr() as *mut _, &mut count, ptr::null_mut()); + let handles = BNGetSymbolsByName( + self.as_ref().handle, + raw_name.as_ref().as_ptr() as *mut _, + &mut count, + ptr::null_mut(), + ); Array::new(handles, count, ()) } @@ -287,55 +327,96 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { let mut count = 0; let len = range.end.wrapping_sub(range.start); - let handles = BNGetSymbolsInRange(self.as_ref().handle, range.start, len, &mut count, ptr::null_mut()); + let handles = BNGetSymbolsInRange( + self.as_ref().handle, + range.start, + len, + &mut count, + ptr::null_mut(), + ); Array::new(handles, count, ()) } } - fn symbols_of_type(&self, ty: SymType) -> Array<Symbol> { + fn symbols_of_type(&self, ty: SymbolType) -> Array<Symbol> { unsafe { let mut count = 0; - let handles = BNGetSymbolsOfType(self.as_ref().handle, ty.into(), &mut count, ptr::null_mut()); + let handles = + BNGetSymbolsOfType(self.as_ref().handle, ty.into(), &mut count, ptr::null_mut()); Array::new(handles, count, ()) } } - fn symbols_of_type_in_range(&self, ty: SymType, range: ops::Range<u64>) -> Array<Symbol> { + fn symbols_of_type_in_range(&self, ty: SymbolType, range: ops::Range<u64>) -> Array<Symbol> { unsafe { let mut count = 0; let len = range.end.wrapping_sub(range.start); - let handles = BNGetSymbolsOfTypeInRange(self.as_ref().handle, ty.into(), range.start, len, &mut count, ptr::null_mut()); + let handles = BNGetSymbolsOfTypeInRange( + self.as_ref().handle, + ty.into(), + range.start, + len, + &mut count, + ptr::null_mut(), + ); Array::new(handles, count, ()) } } fn define_auto_symbol(&self, sym: &Symbol) { - unsafe { BNDefineAutoSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNDefineAutoSymbol(self.as_ref().handle, sym.handle); + } } - fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>(&self, sym: &Symbol, plat: &Platform, ty: T) { + fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>( + &self, + sym: &Symbol, + plat: &Platform, + ty: T, + ) { let raw_type = if let Some(t) = ty.into() { t.handle } else { ptr::null_mut() }; - unsafe { BNDefineAutoSymbolAndVariableOrFunction(self.as_ref().handle, plat.handle, sym.handle, raw_type); } + unsafe { + BNDefineAutoSymbolAndVariableOrFunction( + self.as_ref().handle, + plat.handle, + sym.handle, + raw_type, + ); + } } fn undefine_auto_symbol(&self, sym: &Symbol) { - unsafe { BNUndefineAutoSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNUndefineAutoSymbol(self.as_ref().handle, sym.handle); + } } fn define_user_symbol(&self, sym: &Symbol) { - unsafe { BNDefineUserSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNDefineUserSymbol(self.as_ref().handle, sym.handle); + } } fn undefine_user_symbol(&self, sym: &Symbol) { - unsafe { BNUndefineUserSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNUndefineUserSymbol(self.as_ref().handle, sym.handle); + } + } + + fn define_user_type<S: BnStrCompatible>(&self, name: S, type_obj: &Type) { + unsafe { + let mut qualified_name = QualifiedName::from(name); + BNDefineUserAnalysisType(self.as_ref().handle, &mut qualified_name.0, type_obj.handle) + } } fn segments(&self) -> Array<Segment> { @@ -349,7 +430,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn segment_at(&self, addr: u64) -> Option<Segment> { unsafe { - let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr); + let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr); if !raw_seg.is_null() { Some(Segment::from_raw(raw_seg)) } else { @@ -370,20 +451,24 @@ pub trait BinaryViewExt: BinaryViewBase { let name = name.as_bytes_with_nul(); let name_ptr = name.as_ref().as_ptr() as *mut _; - unsafe { BNRemoveAutoSection(self.as_ref().handle, name_ptr); } + unsafe { + BNRemoveAutoSection(self.as_ref().handle, name_ptr); + } } fn remove_user_section<S: BnStrCompatible>(&self, name: S) { let name = name.as_bytes_with_nul(); let name_ptr = name.as_ref().as_ptr() as *mut _; - unsafe { BNRemoveUserSection(self.as_ref().handle, name_ptr); } + unsafe { + BNRemoveUserSection(self.as_ref().handle, name_ptr); + } } fn section_by_name<S: BnStrCompatible>(&self, name: S) -> Result<Section> { unsafe { let raw_name = name.as_bytes_with_nul(); - let name_ptr = raw_name.as_ref().as_ptr() as * mut _; + let name_ptr = raw_name.as_ref().as_ptr() as *mut _; let raw_section = BNGetSectionByName(self.as_ref().handle, name_ptr); if raw_section.is_null() { @@ -413,15 +498,21 @@ pub trait BinaryViewExt: BinaryViewBase { } fn add_auto_function(&self, plat: &Platform, addr: u64) { - unsafe { BNAddFunctionForAnalysis(self.as_ref().handle, plat.handle, addr); } + unsafe { + BNAddFunctionForAnalysis(self.as_ref().handle, plat.handle, addr); + } } fn add_entry_point(&self, plat: &Platform, addr: u64) { - unsafe { BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr); } + unsafe { + BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr); + } } fn create_user_function(&self, plat: &Platform, addr: u64) { - unsafe { BNCreateUserFunction(self.as_ref().handle, plat.handle, addr); } + unsafe { + BNCreateUserFunction(self.as_ref().handle, plat.handle, addr); + } } fn has_functions(&self) -> bool { @@ -453,7 +544,8 @@ pub trait BinaryViewExt: BinaryViewBase { fn functions_at(&self, addr: u64) -> Array<Function> { unsafe { let mut count = 0; - let functions = BNGetAnalysisFunctionsForAddress(self.as_ref().handle, addr, &mut count); + let functions = + BNGetAnalysisFunctionsForAddress(self.as_ref().handle, addr, &mut count); Array::new(functions, count, ()) } @@ -494,7 +586,29 @@ pub trait BinaryViewExt: BinaryViewBase { } fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) { - unsafe { BNSetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle, suppress); } + unsafe { + BNSetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle, suppress); + } + } + + fn read_buffer(&self, offset: u64, len: usize) -> Result<DataBuffer> { + let read_buffer = unsafe { BNReadViewBuffer(self.as_ref().handle, offset, len) }; + if read_buffer.is_null() { + Err(()) + } else { + Ok(DataBuffer::from_raw(read_buffer)) + } + } + + fn show_graph_report<S: BnStrCompatible>(&self, raw_name: S, graph: FlowGraph) { + let raw_name = raw_name.as_bytes_with_nul(); + unsafe { + BNShowGraphReport( + self.as_ref().handle, + raw_name.as_ref().as_ptr() as *mut _, + graph.as_ref().handle, + ); + } } } @@ -505,20 +619,22 @@ pub struct BinaryView { pub(crate) handle: *mut BNBinaryView, } -unsafe impl Send for BinaryView {} -unsafe impl Sync for BinaryView {} - impl BinaryView { - pub(crate) unsafe fn from_raw(handle: *mut BNBinaryView) -> Self { + pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self { debug_assert!(!handle.is_null()); Self { handle } } - pub fn from_filename<S: BnStrCompatible>(meta: &FileMetadata, filename: S) -> Result<Ref<Self>> { + pub fn from_filename<S: BnStrCompatible>( + meta: &FileMetadata, + filename: S, + ) -> Result<Ref<Self>> { let file = filename.as_bytes_with_nul(); - let handle = unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ref().as_ptr() as *mut _) }; + let handle = unsafe { + BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ref().as_ptr() as *mut _) + }; if handle.is_null() { return Err(()); @@ -528,7 +644,8 @@ impl BinaryView { } pub fn from_accessor(meta: &FileMetadata, file: &mut FileAccessor) -> Result<Ref<Self>> { - let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.api_object as *mut _) }; + let handle = + unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.api_object as *mut _) }; if handle.is_null() { return Err(()); @@ -538,7 +655,9 @@ impl BinaryView { } pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Result<Ref<Self>> { - let handle = unsafe { BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) }; + let handle = unsafe { + BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) + }; if handle.is_null() { return Err(()); @@ -548,17 +667,9 @@ impl BinaryView { } } -impl AsRef<BinaryView> for BinaryView { - fn as_ref(&self) -> &Self { - self - } -} - impl BinaryViewBase for BinaryView { fn read(&self, buf: &mut [u8], offset: u64) -> usize { - unsafe { - BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) - } + unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) } } fn write(&self, offset: u64, data: &[u8]) -> usize { @@ -630,14 +741,6 @@ impl BinaryViewBase for BinaryView { } } -impl ToOwned for BinaryView { - type Owned = Ref<Self>; - - fn to_owned(&self) -> Self::Owned { - unsafe { RefCountable::inc_ref(self) } - } -} - unsafe impl RefCountable for BinaryView { unsafe fn inc_ref(handle: &Self) -> Ref<Self> { Ref::new(Self { @@ -650,691 +753,19 @@ unsafe impl RefCountable for BinaryView { } } -pub trait BinaryViewTypeBase: AsRef<BinaryViewType> { - fn is_valid_for(&self, data: &BinaryView) -> bool; - - fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> { - unsafe { - Ref::new(Settings::from_raw(BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle))) - } - } -} - -pub trait BinaryViewTypeExt: BinaryViewTypeBase { - fn name(&self) -> BnString { - unsafe { - BnString::from_raw(BNGetBinaryViewTypeName(self.as_ref().0)) - } - } - - fn long_name(&self) -> BnString { - unsafe { - BnString::from_raw(BNGetBinaryViewTypeLongName(self.as_ref().0)) - } - } - - fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) - { - unsafe { - BNRegisterArchitectureForViewType(self.as_ref().0, id, endianness, arch.as_ref().0); - } - } - - fn register_platform(&self, id: u32, plat: &Platform) - { - let arch = plat.arch(); - - unsafe { - BNRegisterPlatformForViewType(self.as_ref().0, id, arch.0, plat.handle); - } - } - - fn open(&self, data: &BinaryView) -> Result<Ref<BinaryView>> { - let handle = unsafe { BNCreateBinaryViewOfType(self.as_ref().0, data.handle) }; - - if handle.is_null() { - error!("failed to create BinaryView of BinaryViewType '{}'", self.name()); - return Err(()); - } - - unsafe { - Ok(Ref::new(BinaryView::from_raw(handle))) - } - } -} - -impl<T: BinaryViewTypeBase> BinaryViewTypeExt for T {} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct BinaryViewType(*mut BNBinaryViewType); - -unsafe impl Send for BinaryViewType {} -unsafe impl Sync for BinaryViewType {} - -impl BinaryViewType { - pub fn list_all() -> Array<BinaryViewType> { - unsafe { - let mut count: usize = 0; - let types = BNGetBinaryViewTypes(&mut count as *mut _); - - Array::new(types, count, ()) - } - } - - pub fn list_valid_types_for(data: &BinaryView) -> Array<BinaryViewType> { - unsafe { - let mut count: usize = 0; - let types = BNGetBinaryViewTypesForData(data.handle, &mut count as *mut _); - - Array::new(types, count, ()) - } - } - - /// Looks up a BinaryViewType by its short name - pub fn by_name<N: BnStrCompatible>(name: N) -> Result<Self> { - let bytes = name.as_bytes_with_nul(); - - let res = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; - - match res.is_null() { - false => Ok(BinaryViewType(res)), - true => Err(()), - } - } - -} - -impl AsRef<BinaryViewType> for BinaryViewType { +impl AsRef<BinaryView> for BinaryView { fn as_ref(&self) -> &Self { self } } -impl BinaryViewTypeBase for BinaryViewType { - fn is_valid_for(&self, data: &BinaryView) -> bool { - unsafe { BNIsBinaryViewTypeValidForData(self.0, data.handle) } - } - - fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> { - unsafe { - Ref::new(Settings::from_raw(BNGetBinaryViewLoadSettingsForData(self.0, data.handle))) - } - } -} - -unsafe impl CoreOwnedArrayProvider for BinaryViewType { - type Raw = *mut BNBinaryViewType; - type Context = (); - - unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { - BNFreeBinaryViewTypeList(raw); - } -} - -unsafe impl<'a> CoreOwnedArrayWrapper<'a> for BinaryViewType { - type Wrapped = BinaryViewType; - - unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped { - BinaryViewType(*raw) - } -} - -pub unsafe trait CustomBinaryView: 'static + BinaryViewBase + Sync + Sized { - type Args: Send; - - fn new(handle: BinaryView, args: &Self::Args) -> Result<Self>; - fn init(&self, args: Self::Args) -> Result<()>; -} - -pub trait CustomBinaryViewType: 'static + BinaryViewTypeBase + Sync { - fn create_custom_view<'builder>(&self, data: &BinaryView, builder: CustomViewBuilder<'builder, Self>) -> Result<CustomView<'builder>>; -} - -/// Represents a request from the core to instantiate a custom BinaryView -pub struct CustomViewBuilder<'a, T: CustomBinaryViewType + ?Sized> { - view_type: &'a T, - actual_parent: &'a BinaryView, -} - -/// Represents a partially initialized custom `BinaryView` that should be returned to the core -/// from the `create_custom_view` method of a `CustomBinaryViewType`. -#[must_use] -pub struct CustomView<'builder> { - // this object can't actually be treated like a real - // BinaryView as it isn't fully initialized until the - // core receives it from the BNCustomBinaryViewType::create - // callback. - handle: Ref<BinaryView>, - _builder: PhantomData<&'builder ()>, -} - - -/// Registers a custom `BinaryViewType` with the core. -/// -/// The `constructor` argument is called immediately after successful registration of the type with -/// the core. The `BinaryViewType` argument passed to `constructor` is the object that the -/// `AsRef<BinaryViewType>` -/// implementation of the `CustomBinaryViewType` must return. -pub fn register_view_type<S, T, F>(name: S, long_name: S, constructor: F) -> &'static T -where - S: BnStrCompatible, - T: CustomBinaryViewType, - F: FnOnce(BinaryViewType) -> T, -{ - extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool - where - T: CustomBinaryViewType - { - ffi_wrap!("BinaryViewTypeBase::is_valid_for", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::from_raw(data); - - view_type.is_valid_for(&data) - }) - } - - extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView - where - T: CustomBinaryViewType - { - ffi_wrap!("BinaryViewTypeBase::create", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::from_raw(data); - - let builder = CustomViewBuilder { - view_type: view_type, - actual_parent: &data, - }; - - if let Ok(bv) = view_type.create_custom_view(&data, builder) { - // force a leak of the Ref; failure to do this would result - // in the refcount going to 0 in the process of returning it - // to the core -- we're transferring ownership of the Ref here - Ref::into_raw(bv.handle).handle - } else { - error!("CustomBinaryViewType::create_custom_view returned Err"); - - ptr::null_mut() - } - }) - } - - extern "C" fn cb_parse<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView - where - T: CustomBinaryViewType - { - ffi_wrap!("BinaryViewTypeBase::parse", unsafe { - ptr::null_mut() - }) - } - - extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings - where - T: CustomBinaryViewType - { - ffi_wrap!("BinaryViewTypeBase::load_settings", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::from_raw(data); - - Ref::into_raw(view_type.load_settings_for_data(&data)).handle - }) - } - - let name = name.as_bytes_with_nul(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - - let long_name = long_name.as_bytes_with_nul(); - let long_name_ptr = long_name.as_ref().as_ptr() as *mut _; - - let ctxt = Box::new(unsafe { mem::uninitialized::<T>() }); - let ctxt = Box::into_raw(ctxt); - - let mut bn_obj = BNCustomBinaryViewType { - context: ctxt as *mut _, - create: Some(cb_create::<T>), - parse: Some(cb_parse::<T>), - isValidForData: Some(cb_valid::<T>), - getLoadSettingsForData: Some(cb_load_settings::<T>), - }; - - unsafe { - let res = BNRegisterBinaryViewType(name_ptr, long_name_ptr, &mut bn_obj as *mut _); - - if res.is_null() { - // avoid leaking the space allocated for the type, but also - // avoid running its Drop impl (if any -- not that there should - // be one since view types live for the life of the process) - mem::forget(*Box::from_raw(ctxt)); - - panic!("bvt registration failed"); - } - - ptr::write(ctxt, constructor(BinaryViewType(res))); - - &*ctxt - } -} - -impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { - /// Begins creating a custom BinaryView. - /// - /// This function may only be called from the `create_custom_view` function of a - /// `CustomBinaryViewType`. - /// - /// `parent` specifies the view that the core will treat as the parent view, that - /// Segments created against the created view will be backed by `parent`. It will - /// usually be (but is not required to be) the `data` argument of the `create_custom_view` - /// callback. - /// - /// `constructor` will not be called until well after the value returned by this function - /// has been returned by `create_custom_view` callback to the core, and may not ever - /// be called if the value returned by this function is dropped or leaked. - /// - /// # Errors - /// - /// This function will fail if the `FileMetadata` object associated with the *expected* parent - /// (i.e., the `data` argument passed to the `create_custom_view` function) already has an - /// associated `BinaryView` of the same `CustomBinaryViewType`. Multiple `BinaryView` objects - /// of the same `BinaryViewType` belonging to the same `FileMetadata` object is prohibited and - /// can cause strange, delayed segmentation faults. - /// - /// # Safety - /// - /// `constructor` should avoid doing anything with the object it returns, especially anything - /// that would cause the core to invoke any of the `BinaryViewBase` methods. The core isn't - /// going to consider the object fully initialized until after that callback has run. - /// - /// The `BinaryView` argument passed to the constructor function is the object that is expected - /// to be returned by the `AsRef<BinaryView>` implementation required by the `BinaryViewBase` trait. - /// TODO FIXME welp this is broke going to need 2 init callbacks - pub fn create<V>(self, parent: &BinaryView, view_args: V::Args) -> Result<CustomView<'a>> - where - V: CustomBinaryView, - { - let file = self.actual_parent.metadata(); - let view_type = self.view_type; - - let view_name = view_type.name(); - - if let Ok(bv) = file.get_view_of_type(view_name.as_cstr()) { - // while it seems to work most of the time, you can get really unlucky - // if the a free of the existing view of the same type kicks off while - // BNCreateBinaryViewOfType is still running. the freeObject callback - // will run for the new view before we've even finished initializing, - // and that's all she wrote. - // - // even if we deal with it gracefully in cb_free_object, - // BNCreateBinaryViewOfType is still going to crash, so we're just - // going to try and stop this from happening in the first place. - error!("attempt to create duplicate view of type '{}' (existing: {:?})", view_name.as_str(), bv.handle); - - return Err(()); - } - - // wildly unsafe struct representing the context of a BNCustomBinaryView - // this type should *never* be allowed to drop as the fields are in varying - // states of uninitialized/already consumed throughout the life of the object. - struct CustomViewContext<V> - where - V: CustomBinaryView, - { - view: V, - raw_handle: *mut BNBinaryView, - initialized: bool, - args: V::Args, - } - - extern "C" fn cb_init<V>(ctxt: *mut c_void) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::init", unsafe { - let context = &mut *(ctxt as *mut CustomViewContext<V>); - let handle = BinaryView::from_raw(context.raw_handle); - - if let Ok(v) = V::new(handle, &context.args) { - ptr::write(&mut context.view, v); - context.initialized = true; - - if context.view.init(ptr::read(&context.args)).is_ok() { - true - } else { - error!("CustomBinaryView::init failed; custom view returned Err"); - false - } - } else { - error!("CustomBinaryView::new failed; custom view returned Err"); - false - } - }) - } - - extern "C" fn cb_free_object<V>(ctxt: *mut c_void) - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::freeObject", unsafe { - let context = ctxt as *mut CustomViewContext<V>; - let context = *Box::from_raw(context); - - if context.initialized { - mem::forget(context.args); // already consumed - mem::drop(context.view); // cb_init was called - } else { - mem::drop(context.args); // never consumed - mem::forget(context.view); // cb_init was not called, is uninit - - if context.raw_handle.is_null() { - // being called here is essentially a guarantee that BNCreateBinaryViewOfType - // is above above us on the call stack somewhere -- no matter what we do, a crash - // is pretty much certain at this point. - // - // this has been observed when two views of the same BinaryViewType are created - // against the same BNFileMetaData object, and one of the views gets freed while - // the second one is being initialized -- somehow the partially initialized one - // gets freed before BNCreateBinaryViewOfType returns. - // - // multiples views of the same BinaryViewType in a BNFileMetaData object are - // prohibited, so an API contract was violated in order to get here. - // - // if we're here, it's too late to do anything about it, though we can at least not - // run the destructor on the custom view since that memory is unitialized. - error!("BinaryViewBase::freeObject called on partially initialized object! crash imminent!"); - } else if !context.initialized { - // making it here means somebody went out of their way to leak a BinaryView - // after calling BNCreateCustomView and never gave the BNBinaryView handle - // to the core (which would have called cb_init) - // - // the result is a half-initialized BinaryView that the core will happily hand out - // references to via BNGetFileViewofType even though it was never initialized - // all the way. - // - // TODO update when this corner case gets fixed in the core? - // - // we can't do anything to prevent this, but we can at least have the crash - // not be our fault. - error!("BinaryViewBase::freeObject called on leaked/never initialized custom view!"); - } - } - }) - } - - extern "C" fn cb_read<V>(ctxt: *mut c_void, dest: *mut c_void, offset: u64, len: usize) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::read", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - let dest = slice::from_raw_parts_mut(dest as *mut u8, len); - - context.view.read(dest, offset) - }) - } - - extern "C" fn cb_write<V>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::write", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - let src = slice::from_raw_parts(src as *const u8, len); - - context.view.write(offset, src) - }) - } - - extern "C" fn cb_insert<V>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::insert", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - let src = slice::from_raw_parts(src as *const u8, len); - - context.view.insert(offset, src) - }) - } - - extern "C" fn cb_remove<V>(ctxt: *mut c_void, offset: u64, len: u64) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::remove", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.remove(offset, len as usize) - }) - } - - extern "C" fn cb_modification<V>(ctxt: *mut c_void, offset: u64) -> ModificationStatus - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::modification_status", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.modification_status(offset) - }) - } - - extern "C" fn cb_offset_valid<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::offset_valid", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.offset_valid(offset) - }) - } - - extern "C" fn cb_offset_readable<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::readable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.offset_readable(offset) - }) - } - - extern "C" fn cb_offset_writable<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::writable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.offset_writable(offset) - }) - } - - extern "C" fn cb_offset_executable<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::offset_executable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.offset_executable(offset) - }) - } - - extern "C" fn cb_offset_backed_by_file<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.offset_backed_by_file(offset) - }) - } - - extern "C" fn cb_next_valid_offset<V>(ctxt: *mut c_void, offset: u64) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.next_valid_offset_after(offset) - }) - } - - extern "C" fn cb_start<V>(ctxt: *mut c_void) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::start", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.start() - }) - } - - extern "C" fn cb_length<V>(ctxt: *mut c_void) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::len", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.len() as u64 - }) - } - - extern "C" fn cb_entry_point<V>(ctxt: *mut c_void) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::entry_point", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.entry_point() - }) - } - - extern "C" fn cb_executable<V>(ctxt: *mut c_void) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::executable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.executable() - }) - } - - extern "C" fn cb_endianness<V>(ctxt: *mut c_void) -> Endianness - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::default_endianness", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.default_endianness() - }) - } - - extern "C" fn cb_relocatable<V>(ctxt: *mut c_void) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::relocatable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.relocatable() - }) - } - - extern "C" fn cb_address_size<V>(ctxt: *mut c_void) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::address_size", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.view.address_size() - }) - } - - extern "C" fn cb_save<V>(ctxt: *mut c_void, _fa: *mut BNFileAccessor) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::save", unsafe { - let _context = &*(ctxt as *mut CustomViewContext<V>); - false - }) - } - - let ctxt = Box::new(CustomViewContext::<V> { - view: unsafe { mem::uninitialized() }, - raw_handle: ptr::null_mut(), - initialized: false, - args: view_args, - }); - - let ctxt = Box::into_raw(ctxt); - - let mut bn_obj = BNCustomBinaryView { - context: ctxt as *mut _, - init: Some(cb_init::<V>), - freeObject: Some(cb_free_object::<V>), - externalRefTaken: None, - externalRefReleased: None, - read: Some(cb_read::<V>), - write: Some(cb_write::<V>), - insert: Some(cb_insert::<V>), - remove: Some(cb_remove::<V>), - getModification: Some(cb_modification::<V>), - isValidOffset: Some(cb_offset_valid::<V>), - isOffsetReadable: Some(cb_offset_readable::<V>), - isOffsetWritable: Some(cb_offset_writable::<V>), - isOffsetExecutable: Some(cb_offset_executable::<V>), - isOffsetBackedByFile: Some(cb_offset_backed_by_file::<V>), - getNextValidOffset: Some(cb_next_valid_offset::<V>), - getStart: Some(cb_start::<V>), - getLength: Some(cb_length::<V>), - getEntryPoint: Some(cb_entry_point::<V>), - isExecutable: Some(cb_executable::<V>), - getDefaultEndianness: Some(cb_endianness::<V>), - isRelocatable: Some(cb_relocatable::<V>), - getAddressSize: Some(cb_address_size::<V>), - save: Some(cb_save::<V>), - }; - - unsafe { - let res = BNCreateCustomBinaryView(view_name.as_cstr().as_ptr(), file.handle, parent.handle, &mut bn_obj); - - if res.is_null() { - // TODO not sure when this can even happen, let alone what we're supposed to do about - // it. cb_init isn't normally called until later, and cb_free_object definitely won't - // have been called, so we'd at least be on the hook for freeing that stuff... - // probably. - // - // no idea how to force this to fail so I can test this, so just going to do the - // reasonable thing and panic. - panic!("failed to create custom binary view!"); - } - - (*ctxt).raw_handle = res; - - Ok(CustomView { - handle: Ref::new(BinaryView::from_raw(res)), - _builder: PhantomData, - }) - } - } +impl ToOwned for BinaryView { + type Owned = Ref<Self>; - pub fn wrap_existing(self, wrapped_view: Ref<BinaryView>) -> Result<CustomView<'a>> - { - Ok(CustomView { - handle: wrapped_view, - _builder: PhantomData, - }) + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } } } +unsafe impl Send for BinaryView {} +unsafe impl Sync for BinaryView {} diff --git a/rust/src/callingconvention.rs b/rust/src/callingconvention.rs index a607b67f..51fe412d 100644 --- a/rust/src/callingconvention.rs +++ b/rust/src/callingconvention.rs @@ -1,9 +1,23 @@ +// Copyright 2021 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::borrow::Borrow; +use std::marker::PhantomData; use std::mem; +use std::os::raw::c_void; use std::ptr; use std::slice; -use std::os::raw::c_void; -use std::borrow::Borrow; -use std::marker::PhantomData; use binaryninjacore_sys::*; @@ -27,6 +41,7 @@ pub trait CallingConventionBase: Sync { fn arg_registers_shared_index(&self) -> bool; fn reserved_stack_space_for_arg_registers(&self) -> bool; fn stack_adjusted_on_return(&self) -> bool; + fn is_eligible_for_heuristics(&self) -> bool; fn return_int_reg(&self) -> Option<<Self::Arch as Architecture>::Register>; fn return_hi_int_reg(&self) -> Option<<Self::Arch as Architecture>::Register>; @@ -41,7 +56,7 @@ pub fn register_calling_convention<A, N, C>(arch: &A, name: N, cc: C) -> Ref<Cal where A: Architecture, N: BnStrCompatible, - C: 'static + CallingConventionBase<Arch=A>, + C: 'static + CallingConventionBase<Arch = A>, { struct CustomCallingConventionContext<C> where @@ -60,7 +75,10 @@ where }) } - fn alloc_register_list<I: Iterator<Item=u32> + ExactSizeIterator>(items: I, count: &mut usize) -> *mut u32 { + fn alloc_register_list<I: Iterator<Item = u32> + ExactSizeIterator>( + items: I, + count: &mut usize, + ) -> *mut u32 { let len = items.len(); *count = len; @@ -159,11 +177,14 @@ where where C: CallingConventionBase, { - ffi_wrap!("CallingConvention::reserved_stack_space_for_arg_registers", unsafe { - let ctxt = &*(ctxt as *mut CustomCallingConventionContext<C>); + ffi_wrap!( + "CallingConvention::reserved_stack_space_for_arg_registers", + unsafe { + let ctxt = &*(ctxt as *mut CustomCallingConventionContext<C>); - ctxt.cc.reserved_stack_space_for_arg_registers() - }) + ctxt.cc.reserved_stack_space_for_arg_registers() + } + ) } extern "C" fn cb_stack_adjusted_on_return<C>(ctxt: *mut c_void) -> bool @@ -177,6 +198,17 @@ where }) } + extern "C" fn cb_is_eligible_for_heuristics<C>(ctxt: *mut c_void) -> bool + where + C: CallingConventionBase, + { + ffi_wrap!("CallingConvention::is_eligible_for_heuristics", unsafe { + let ctxt = &*(ctxt as *mut CustomCallingConventionContext<C>); + + ctxt.cc.is_eligible_for_heuristics() + }) + } + extern "C" fn cb_return_int_reg<C>(ctxt: *mut c_void) -> u32 where C: CallingConventionBase, @@ -233,7 +265,10 @@ where }) } - extern "C" fn cb_implicitly_defined_registers<C>(ctxt: *mut c_void, count: *mut usize) -> *mut u32 + extern "C" fn cb_implicitly_defined_registers<C>( + ctxt: *mut c_void, + count: *mut usize, + ) -> *mut u32 where C: CallingConventionBase, { @@ -245,8 +280,12 @@ where }) } - extern "C" fn cb_incoming_reg_value<C>(_ctxt: *mut c_void, _reg: u32, _func: *mut BNFunction, val: *mut BNRegisterValue) - where + extern "C" fn cb_incoming_reg_value<C>( + _ctxt: *mut c_void, + _reg: u32, + _func: *mut BNFunction, + val: *mut BNRegisterValue, + ) where C: CallingConventionBase, { ffi_wrap!("CallingConvention::incoming_reg_value", unsafe { @@ -258,8 +297,12 @@ where }) } - extern "C" fn cb_incoming_flag_value<C>(_ctxt: *mut c_void, _flag: u32, _func: *mut BNFunction, val: *mut BNRegisterValue) - where + extern "C" fn cb_incoming_flag_value<C>( + _ctxt: *mut c_void, + _flag: u32, + _func: *mut BNFunction, + val: *mut BNRegisterValue, + ) where C: CallingConventionBase, { ffi_wrap!("CallingConvention::incoming_flag_value", unsafe { @@ -271,23 +314,37 @@ where }) } - extern "C" fn cb_incoming_var_for_param<C>(ctxt: *mut c_void, var: *const BNVariable, _func: *mut BNFunction, param: *mut BNVariable) - where + extern "C" fn cb_incoming_var_for_param<C>( + ctxt: *mut c_void, + var: *const BNVariable, + _func: *mut BNFunction, + param: *mut BNVariable, + ) where C: CallingConventionBase, { ffi_wrap!("CallingConvention::incoming_var_for_param", unsafe { let ctxt = &*(ctxt as *mut CustomCallingConventionContext<C>); - ptr::write(param, BNGetDefaultIncomingVariableForParameterVariable(ctxt.raw_handle, var)); + ptr::write( + param, + BNGetDefaultIncomingVariableForParameterVariable(ctxt.raw_handle, var), + ); }) } - extern "C" fn cb_incoming_param_for_var<C>(ctxt: *mut c_void, var: *const BNVariable, _func: *mut BNFunction, param: *mut BNVariable) - where + extern "C" fn cb_incoming_param_for_var<C>( + ctxt: *mut c_void, + var: *const BNVariable, + _func: *mut BNFunction, + param: *mut BNVariable, + ) where C: CallingConventionBase, { ffi_wrap!("CallingConvention::incoming_var_for_param", unsafe { let ctxt = &*(ctxt as *mut CustomCallingConventionContext<C>); - ptr::write(param, BNGetDefaultParameterVariableForIncomingVariable(ctxt.raw_handle, var)); + ptr::write( + param, + BNGetDefaultParameterVariableForIncomingVariable(ctxt.raw_handle, var), + ); }) } @@ -310,6 +367,7 @@ where areArgumentRegistersSharedIndex: Some(cb_arg_shared_index::<C>), isStackReservedForArgumentRegisters: Some(cb_stack_reserved_arg_regs::<C>), isStackAdjustedOnReturn: Some(cb_stack_adjusted_on_return::<C>), + isEligibleForHeuristics: Some(cb_is_eligible_for_heuristics::<C>), getIntegerReturnValueRegister: Some(cb_return_int_reg::<C>), getHighIntegerReturnValueRegister: Some(cb_return_hi_int_reg::<C>), @@ -374,7 +432,6 @@ impl<A: Architecture> Hash for CallingConvention<A> { } } - impl<A: Architecture> CallingConventionBase for CallingConvention<A> { type Arch = A; @@ -384,9 +441,13 @@ impl<A: Architecture> CallingConventionBase for CallingConvention<A> { let regs = BNGetCallerSavedRegisters(self.handle, &mut count); let arch = self.arch_handle.borrow(); - let res = slice::from_raw_parts(regs, count).iter().map(|&r| { - arch.register_from_id(r).expect("bad reg id from CallingConvention") - }).collect(); + let res = slice::from_raw_parts(regs, count) + .iter() + .map(|&r| { + arch.register_from_id(r) + .expect("bad reg id from CallingConvention") + }) + .collect(); BNFreeRegisterList(regs); @@ -400,9 +461,13 @@ impl<A: Architecture> CallingConventionBase for CallingConvention<A> { let regs = BNGetCalleeSavedRegisters(self.handle, &mut count); let arch = self.arch_handle.borrow(); - let res = slice::from_raw_parts(regs, count).iter().map(|&r| { - arch.register_from_id(r).expect("bad reg id from CallingConvention") - }).collect(); + let res = slice::from_raw_parts(regs, count) + .iter() + .map(|&r| { + arch.register_from_id(r) + .expect("bad reg id from CallingConvention") + }) + .collect(); BNFreeRegisterList(regs); @@ -430,38 +495,34 @@ impl<A: Architecture> CallingConventionBase for CallingConvention<A> { unsafe { BNIsStackAdjustedOnReturn(self.handle) } } + fn is_eligible_for_heuristics(&self) -> bool { + false + } + fn return_int_reg(&self) -> Option<A::Register> { match unsafe { BNGetIntegerReturnValueRegister(self.handle) } { - id if id < 0x8000_0000 => { - self.arch_handle.borrow().register_from_id(id) - } + id if id < 0x8000_0000 => self.arch_handle.borrow().register_from_id(id), _ => None, } } fn return_hi_int_reg(&self) -> Option<A::Register> { match unsafe { BNGetHighIntegerReturnValueRegister(self.handle) } { - id if id < 0x8000_0000 => { - self.arch_handle.borrow().register_from_id(id) - } + id if id < 0x8000_0000 => self.arch_handle.borrow().register_from_id(id), _ => None, } } fn return_float_reg(&self) -> Option<A::Register> { match unsafe { BNGetFloatReturnValueRegister(self.handle) } { - id if id < 0x8000_0000 => { - self.arch_handle.borrow().register_from_id(id) - } + id if id < 0x8000_0000 => self.arch_handle.borrow().register_from_id(id), _ => None, } } fn global_pointer_reg(&self) -> Option<A::Register> { match unsafe { BNGetGlobalPointerRegister(self.handle) } { - id if id < 0x8000_0000 => { - self.arch_handle.borrow().register_from_id(id) - } + id if id < 0x8000_0000 => self.arch_handle.borrow().register_from_id(id), _ => None, } } @@ -502,6 +563,7 @@ pub struct ConventionBuilder<A: Architecture> { arg_registers_shared_index: bool, reserved_stack_space_for_arg_registers: bool, stack_adjusted_on_return: bool, + is_eligible_for_heuristics: bool, return_int_reg: Option<A::Register>, return_hi_int_reg: Option<A::Register>, @@ -524,13 +586,14 @@ macro_rules! bool_arg { self.$name = val; self } - } + }; } macro_rules! reg_list { ($name:ident) => { pub fn $name(mut self, regs: &[&str]) -> Self { - { // FIXME NLL + { + // FIXME NLL let arch = self.arch_handle.borrow(); let arch_regs = regs.iter().filter_map(|&r| arch.register_by_name(r)); @@ -539,20 +602,21 @@ macro_rules! reg_list { self } - } + }; } macro_rules! reg { ($name:ident) => { pub fn $name(mut self, reg: &str) -> Self { - { // FIXME NLL + { + // FIXME NLL let arch = self.arch_handle.borrow(); self.$name = arch.register_by_name(reg); } self } - } + }; } impl<A: Architecture> ConventionBuilder<A> { @@ -566,6 +630,7 @@ impl<A: Architecture> ConventionBuilder<A> { arg_registers_shared_index: false, reserved_stack_space_for_arg_registers: false, stack_adjusted_on_return: false, + is_eligible_for_heuristics: false, return_int_reg: None, return_hi_int_reg: None, @@ -635,6 +700,10 @@ impl<A: Architecture> CallingConventionBase for ConventionBuilder<A> { self.stack_adjusted_on_return } + fn is_eligible_for_heuristics(&self) -> bool { + self.is_eligible_for_heuristics + } + fn return_int_reg(&self) -> Option<A::Register> { self.return_int_reg.clone() } diff --git a/rust/src/command.rs b/rust/src/command.rs index 70839f6b..7dbc7436 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -1,9 +1,21 @@ -use binaryninjacore_sys::{BNRegisterPluginCommand, - BNRegisterPluginCommandForAddress, - BNRegisterPluginCommandForRange, - BNRegisterPluginCommandForFunction, - BNBinaryView, - BNFunction}; +// Copyright 2021 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::{ + BNBinaryView, BNFunction, BNRegisterPluginCommand, BNRegisterPluginCommandForAddress, + BNRegisterPluginCommandForFunction, BNRegisterPluginCommandForRange, +}; use std::ops::Range; use std::os::raw::c_void; @@ -68,9 +80,13 @@ where let ctxt = Box::into_raw(Box::new(command)); unsafe { - BNRegisterPluginCommand(name_ptr, desc_ptr, - Some(cb_action::<C>), Some(cb_valid::<C>), - ctxt as *mut _); + BNRegisterPluginCommand( + name_ptr, + desc_ptr, + Some(cb_action::<C>), + Some(cb_valid::<C>), + ctxt as *mut _, + ); } } @@ -130,9 +146,13 @@ where let ctxt = Box::into_raw(Box::new(command)); unsafe { - BNRegisterPluginCommandForAddress(name_ptr, desc_ptr, - Some(cb_action::<C>), Some(cb_valid::<C>), - ctxt as *mut _); + BNRegisterPluginCommandForAddress( + name_ptr, + desc_ptr, + Some(cb_action::<C>), + Some(cb_valid::<C>), + ctxt as *mut _, + ); } } @@ -167,11 +187,16 @@ where let cmd = &*(ctxt as *const C); let view = BinaryView::from_raw(view); - cmd.action(&view, addr .. addr.wrapping_add(len)); + cmd.action(&view, addr..addr.wrapping_add(len)); }) } - extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64) -> bool + extern "C" fn cb_valid<C>( + ctxt: *mut c_void, + view: *mut BNBinaryView, + addr: u64, + len: u64, + ) -> bool where C: RangeCommand, { @@ -179,7 +204,7 @@ where let cmd = &*(ctxt as *const C); let view = BinaryView::from_raw(view); - cmd.valid(&view, addr .. addr.wrapping_add(len)) + cmd.valid(&view, addr..addr.wrapping_add(len)) }) } @@ -192,9 +217,13 @@ where let ctxt = Box::into_raw(Box::new(command)); unsafe { - BNRegisterPluginCommandForRange(name_ptr, desc_ptr, - Some(cb_action::<C>), Some(cb_valid::<C>), - ctxt as *mut _); + BNRegisterPluginCommandForRange( + name_ptr, + desc_ptr, + Some(cb_action::<C>), + Some(cb_valid::<C>), + ctxt as *mut _, + ); } } @@ -234,7 +263,11 @@ where }) } - extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction) -> bool + extern "C" fn cb_valid<C>( + ctxt: *mut c_void, + view: *mut BNBinaryView, + func: *mut BNFunction, + ) -> bool where C: FunctionCommand, { @@ -256,8 +289,12 @@ where let ctxt = Box::into_raw(Box::new(command)); unsafe { - BNRegisterPluginCommandForFunction(name_ptr, desc_ptr, - Some(cb_action::<C>), Some(cb_valid::<C>), - ctxt as *mut _); + BNRegisterPluginCommandForFunction( + name_ptr, + desc_ptr, + Some(cb_action::<C>), + Some(cb_valid::<C>), + ctxt as *mut _, + ); } } diff --git a/rust/src/custombinaryview.rs b/rust/src/custombinaryview.rs new file mode 100644 index 00000000..81272b0b --- /dev/null +++ b/rust/src/custombinaryview.rs @@ -0,0 +1,745 @@ +// Copyright 2021 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::*; + +pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; + +use std::marker::PhantomData; +use std::mem; +use std::os::raw::c_void; +use std::ptr; +use std::slice; + +use crate::architecture::Architecture; +use crate::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt, Result}; +use crate::platform::Platform; +use crate::settings::Settings; +use crate::Endianness; + +use crate::rc::*; +use crate::string::*; + +/// Registers a custom `BinaryViewType` with the core. +/// +/// The `constructor` argument is called immediately after successful registration of the type with +/// the core. The `BinaryViewType` argument passed to `constructor` is the object that the +/// `AsRef<BinaryViewType>` +/// implementation of the `CustomBinaryViewType` must return. +pub fn register_view_type<S, T, F>(name: S, long_name: S, constructor: F) -> &'static T +where + S: BnStrCompatible, + T: CustomBinaryViewType, + F: FnOnce(BinaryViewType) -> T, +{ + extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool + where + T: CustomBinaryViewType, + { + ffi_wrap!("BinaryViewTypeBase::is_valid_for", unsafe { + let view_type = &*(ctxt as *mut T); + let data = BinaryView::from_raw(data); + + view_type.is_valid_for(&data) + }) + } + + extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView + where + T: CustomBinaryViewType, + { + ffi_wrap!("BinaryViewTypeBase::create", unsafe { + let view_type = &*(ctxt as *mut T); + let data = BinaryView::from_raw(data); + + let builder = CustomViewBuilder { + view_type: view_type, + actual_parent: &data, + }; + + if let Ok(bv) = view_type.create_custom_view(&data, builder) { + // force a leak of the Ref; failure to do this would result + // in the refcount going to 0 in the process of returning it + // to the core -- we're transferring ownership of the Ref here + Ref::into_raw(bv.handle).handle + } else { + error!("CustomBinaryViewType::create_custom_view returned Err"); + + ptr::null_mut() + } + }) + } + + extern "C" fn cb_parse<T>(_ctxt: *mut c_void, _data: *mut BNBinaryView) -> *mut BNBinaryView + where + T: CustomBinaryViewType, + { + ffi_wrap!("BinaryViewTypeBase::parse", ptr::null_mut()) + } + + extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings + where + T: CustomBinaryViewType, + { + ffi_wrap!("BinaryViewTypeBase::load_settings", unsafe { + let view_type = &*(ctxt as *mut T); + let data = BinaryView::from_raw(data); + + Ref::into_raw(view_type.load_settings_for_data(&data)).handle + }) + } + + let name = name.as_bytes_with_nul(); + let name_ptr = name.as_ref().as_ptr() as *mut _; + + let long_name = long_name.as_bytes_with_nul(); + let long_name_ptr = long_name.as_ref().as_ptr() as *mut _; + + let ctxt = Box::new(unsafe { mem::zeroed() }); + let ctxt = Box::into_raw(ctxt); + + let mut bn_obj = BNCustomBinaryViewType { + context: ctxt as *mut _, + create: Some(cb_create::<T>), + parse: Some(cb_parse::<T>), + isValidForData: Some(cb_valid::<T>), + getLoadSettingsForData: Some(cb_load_settings::<T>), + }; + + unsafe { + let res = BNRegisterBinaryViewType(name_ptr, long_name_ptr, &mut bn_obj as *mut _); + + if res.is_null() { + // avoid leaking the space allocated for the type, but also + // avoid running its Drop impl (if any -- not that there should + // be one since view types live for the life of the process) + mem::forget(*Box::from_raw(ctxt)); + + panic!("bvt registration failed"); + } + + ptr::write(ctxt, constructor(BinaryViewType(res))); + + &*ctxt + } +} + +pub trait BinaryViewTypeBase: AsRef<BinaryViewType> { + fn is_valid_for(&self, data: &BinaryView) -> bool; + + fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> { + unsafe { + Ref::new(Settings::from_raw( + BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle), + )) + } + } +} + +pub trait BinaryViewTypeExt: BinaryViewTypeBase { + fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNGetBinaryViewTypeName(self.as_ref().0)) } + } + + fn long_name(&self) -> BnString { + unsafe { BnString::from_raw(BNGetBinaryViewTypeLongName(self.as_ref().0)) } + } + + fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) { + unsafe { + BNRegisterArchitectureForViewType(self.as_ref().0, id, endianness, arch.as_ref().0); + } + } + + fn register_platform(&self, id: u32, plat: &Platform) { + let arch = plat.arch(); + + unsafe { + BNRegisterPlatformForViewType(self.as_ref().0, id, arch.0, plat.handle); + } + } + + fn open(&self, data: &BinaryView) -> Result<Ref<BinaryView>> { + let handle = unsafe { BNCreateBinaryViewOfType(self.as_ref().0, data.handle) }; + + if handle.is_null() { + error!( + "failed to create BinaryView of BinaryViewType '{}'", + self.name() + ); + return Err(()); + } + + unsafe { Ok(Ref::new(BinaryView::from_raw(handle))) } + } +} + +impl<T: BinaryViewTypeBase> BinaryViewTypeExt for T {} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct BinaryViewType(pub *mut BNBinaryViewType); + +impl BinaryViewType { + pub fn list_all() -> Array<BinaryViewType> { + unsafe { + let mut count: usize = 0; + let types = BNGetBinaryViewTypes(&mut count as *mut _); + + Array::new(types, count, ()) + } + } + + pub fn list_valid_types_for(data: &BinaryView) -> Array<BinaryViewType> { + unsafe { + let mut count: usize = 0; + let types = BNGetBinaryViewTypesForData(data.handle, &mut count as *mut _); + + Array::new(types, count, ()) + } + } + + /// Looks up a BinaryViewType by its short name + pub fn by_name<N: BnStrCompatible>(name: N) -> Result<Self> { + let bytes = name.as_bytes_with_nul(); + + let res = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; + + match res.is_null() { + false => Ok(BinaryViewType(res)), + true => Err(()), + } + } +} + +impl BinaryViewTypeBase for BinaryViewType { + fn is_valid_for(&self, data: &BinaryView) -> bool { + unsafe { BNIsBinaryViewTypeValidForData(self.0, data.handle) } + } + + fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> { + unsafe { + Ref::new(Settings::from_raw(BNGetBinaryViewLoadSettingsForData( + self.0, + data.handle, + ))) + } + } +} + +unsafe impl CoreOwnedArrayProvider for BinaryViewType { + type Raw = *mut BNBinaryViewType; + type Context = (); + + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeBinaryViewTypeList(raw); + } +} + +unsafe impl<'a> CoreOwnedArrayWrapper<'a> for BinaryViewType { + type Wrapped = BinaryViewType; + + unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped { + BinaryViewType(*raw) + } +} + +impl AsRef<BinaryViewType> for BinaryViewType { + fn as_ref(&self) -> &Self { + self + } +} + +unsafe impl Send for BinaryViewType {} +unsafe impl Sync for BinaryViewType {} + +pub trait CustomBinaryViewType: 'static + BinaryViewTypeBase + Sync { + fn create_custom_view<'builder>( + &self, + data: &BinaryView, + builder: CustomViewBuilder<'builder, Self>, + ) -> Result<CustomView<'builder>>; +} + +/// Represents a request from the core to instantiate a custom BinaryView +pub struct CustomViewBuilder<'a, T: CustomBinaryViewType + ?Sized> { + view_type: &'a T, + actual_parent: &'a BinaryView, +} + +pub unsafe trait CustomBinaryView: 'static + BinaryViewBase + Sync + Sized { + type Args: Send; + + fn new(handle: BinaryView, args: &Self::Args) -> Result<Self>; + fn init(&self, args: Self::Args) -> Result<()>; +} + +/// Represents a partially initialized custom `BinaryView` that should be returned to the core +/// from the `create_custom_view` method of a `CustomBinaryViewType`. +#[must_use] +pub struct CustomView<'builder> { + // this object can't actually be treated like a real + // BinaryView as it isn't fully initialized until the + // core receives it from the BNCustomBinaryViewType::create + // callback. + handle: Ref<BinaryView>, + _builder: PhantomData<&'builder ()>, +} + +impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { + /// Begins creating a custom BinaryView. + /// + /// This function may only be called from the `create_custom_view` function of a + /// `CustomBinaryViewType`. + /// + /// `parent` specifies the view that the core will treat as the parent view, that + /// Segments created against the created view will be backed by `parent`. It will + /// usually be (but is not required to be) the `data` argument of the `create_custom_view` + /// callback. + /// + /// `constructor` will not be called until well after the value returned by this function + /// has been returned by `create_custom_view` callback to the core, and may not ever + /// be called if the value returned by this function is dropped or leaked. + /// + /// # Errors + /// + /// This function will fail if the `FileMetadata` object associated with the *expected* parent + /// (i.e., the `data` argument passed to the `create_custom_view` function) already has an + /// associated `BinaryView` of the same `CustomBinaryViewType`. Multiple `BinaryView` objects + /// of the same `BinaryViewType` belonging to the same `FileMetadata` object is prohibited and + /// can cause strange, delayed segmentation faults. + /// + /// # Safety + /// + /// `constructor` should avoid doing anything with the object it returns, especially anything + /// that would cause the core to invoke any of the `BinaryViewBase` methods. The core isn't + /// going to consider the object fully initialized until after that callback has run. + /// + /// The `BinaryView` argument passed to the constructor function is the object that is expected + /// to be returned by the `AsRef<BinaryView>` implementation required by the `BinaryViewBase` trait. + /// TODO FIXME welp this is broke going to need 2 init callbacks + pub fn create<V>(self, parent: &BinaryView, view_args: V::Args) -> Result<CustomView<'a>> + where + V: CustomBinaryView, + { + let file = self.actual_parent.metadata(); + let view_type = self.view_type; + + let view_name = view_type.name(); + + if let Ok(bv) = file.get_view_of_type(view_name.as_cstr()) { + // while it seems to work most of the time, you can get really unlucky + // if the a free of the existing view of the same type kicks off while + // BNCreateBinaryViewOfType is still running. the freeObject callback + // will run for the new view before we've even finished initializing, + // and that's all she wrote. + // + // even if we deal with it gracefully in cb_free_object, + // BNCreateBinaryViewOfType is still going to crash, so we're just + // going to try and stop this from happening in the first place. + error!( + "attempt to create duplicate view of type '{}' (existing: {:?})", + view_name.as_str(), + bv.handle + ); + + return Err(()); + } + + // wildly unsafe struct representing the context of a BNCustomBinaryView + // this type should *never* be allowed to drop as the fields are in varying + // states of uninitialized/already consumed throughout the life of the object. + struct CustomViewContext<V> + where + V: CustomBinaryView, + { + view: V, + raw_handle: *mut BNBinaryView, + initialized: bool, + args: V::Args, + } + + extern "C" fn cb_init<V>(ctxt: *mut c_void) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::init", unsafe { + let context = &mut *(ctxt as *mut CustomViewContext<V>); + let handle = BinaryView::from_raw(context.raw_handle); + + if let Ok(v) = V::new(handle, &context.args) { + ptr::write(&mut context.view, v); + context.initialized = true; + + if context.view.init(ptr::read(&context.args)).is_ok() { + true + } else { + error!("CustomBinaryView::init failed; custom view returned Err"); + false + } + } else { + error!("CustomBinaryView::new failed; custom view returned Err"); + false + } + }) + } + + extern "C" fn cb_free_object<V>(ctxt: *mut c_void) + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::freeObject", unsafe { + let context = ctxt as *mut CustomViewContext<V>; + let context = *Box::from_raw(context); + + if context.initialized { + mem::forget(context.args); // already consumed + mem::drop(context.view); // cb_init was called + } else { + mem::drop(context.args); // never consumed + mem::forget(context.view); // cb_init was not called, is uninit + + if context.raw_handle.is_null() { + // being called here is essentially a guarantee that BNCreateBinaryViewOfType + // is above above us on the call stack somewhere -- no matter what we do, a crash + // is pretty much certain at this point. + // + // this has been observed when two views of the same BinaryViewType are created + // against the same BNFileMetaData object, and one of the views gets freed while + // the second one is being initialized -- somehow the partially initialized one + // gets freed before BNCreateBinaryViewOfType returns. + // + // multiples views of the same BinaryViewType in a BNFileMetaData object are + // prohibited, so an API contract was violated in order to get here. + // + // if we're here, it's too late to do anything about it, though we can at least not + // run the destructor on the custom view since that memory is unitialized. + error!( + "BinaryViewBase::freeObject called on partially initialized object! crash imminent!" + ); + } else if !context.initialized { + // making it here means somebody went out of their way to leak a BinaryView + // after calling BNCreateCustomView and never gave the BNBinaryView handle + // to the core (which would have called cb_init) + // + // the result is a half-initialized BinaryView that the core will happily hand out + // references to via BNGetFileViewofType even though it was never initialized + // all the way. + // + // TODO update when this corner case gets fixed in the core? + // + // we can't do anything to prevent this, but we can at least have the crash + // not be our fault. + error!("BinaryViewBase::freeObject called on leaked/never initialized custom view!"); + } + } + }) + } + + extern "C" fn cb_read<V>( + ctxt: *mut c_void, + dest: *mut c_void, + offset: u64, + len: usize, + ) -> usize + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::read", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + let dest = slice::from_raw_parts_mut(dest as *mut u8, len); + + context.view.read(dest, offset) + }) + } + + extern "C" fn cb_write<V>( + ctxt: *mut c_void, + offset: u64, + src: *const c_void, + len: usize, + ) -> usize + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::write", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + let src = slice::from_raw_parts(src as *const u8, len); + + context.view.write(offset, src) + }) + } + + extern "C" fn cb_insert<V>( + ctxt: *mut c_void, + offset: u64, + src: *const c_void, + len: usize, + ) -> usize + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::insert", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + let src = slice::from_raw_parts(src as *const u8, len); + + context.view.insert(offset, src) + }) + } + + extern "C" fn cb_remove<V>(ctxt: *mut c_void, offset: u64, len: u64) -> usize + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::remove", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.remove(offset, len as usize) + }) + } + + extern "C" fn cb_modification<V>(ctxt: *mut c_void, offset: u64) -> ModificationStatus + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::modification_status", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.modification_status(offset) + }) + } + + extern "C" fn cb_offset_valid<V>(ctxt: *mut c_void, offset: u64) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::offset_valid", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.offset_valid(offset) + }) + } + + extern "C" fn cb_offset_readable<V>(ctxt: *mut c_void, offset: u64) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::readable", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.offset_readable(offset) + }) + } + + extern "C" fn cb_offset_writable<V>(ctxt: *mut c_void, offset: u64) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::writable", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.offset_writable(offset) + }) + } + + extern "C" fn cb_offset_executable<V>(ctxt: *mut c_void, offset: u64) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::offset_executable", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.offset_executable(offset) + }) + } + + extern "C" fn cb_offset_backed_by_file<V>(ctxt: *mut c_void, offset: u64) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.offset_backed_by_file(offset) + }) + } + + extern "C" fn cb_next_valid_offset<V>(ctxt: *mut c_void, offset: u64) -> u64 + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.next_valid_offset_after(offset) + }) + } + + extern "C" fn cb_start<V>(ctxt: *mut c_void) -> u64 + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::start", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.start() + }) + } + + extern "C" fn cb_length<V>(ctxt: *mut c_void) -> u64 + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::len", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.len() as u64 + }) + } + + extern "C" fn cb_entry_point<V>(ctxt: *mut c_void) -> u64 + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::entry_point", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.entry_point() + }) + } + + extern "C" fn cb_executable<V>(ctxt: *mut c_void) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::executable", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.executable() + }) + } + + extern "C" fn cb_endianness<V>(ctxt: *mut c_void) -> Endianness + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::default_endianness", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.default_endianness() + }) + } + + extern "C" fn cb_relocatable<V>(ctxt: *mut c_void) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::relocatable", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.relocatable() + }) + } + + extern "C" fn cb_address_size<V>(ctxt: *mut c_void) -> usize + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::address_size", unsafe { + let context = &*(ctxt as *mut CustomViewContext<V>); + + context.view.address_size() + }) + } + + extern "C" fn cb_save<V>(ctxt: *mut c_void, _fa: *mut BNFileAccessor) -> bool + where + V: CustomBinaryView, + { + ffi_wrap!("BinaryViewBase::save", unsafe { + let _context = &*(ctxt as *mut CustomViewContext<V>); + false + }) + } + + let ctxt = Box::new(CustomViewContext::<V> { + view: unsafe { mem::zeroed() }, + raw_handle: ptr::null_mut(), + initialized: false, + args: view_args, + }); + + let ctxt = Box::into_raw(ctxt); + + let mut bn_obj = BNCustomBinaryView { + context: ctxt as *mut _, + init: Some(cb_init::<V>), + freeObject: Some(cb_free_object::<V>), + externalRefTaken: None, + externalRefReleased: None, + read: Some(cb_read::<V>), + write: Some(cb_write::<V>), + insert: Some(cb_insert::<V>), + remove: Some(cb_remove::<V>), + getModification: Some(cb_modification::<V>), + isValidOffset: Some(cb_offset_valid::<V>), + isOffsetReadable: Some(cb_offset_readable::<V>), + isOffsetWritable: Some(cb_offset_writable::<V>), + isOffsetExecutable: Some(cb_offset_executable::<V>), + isOffsetBackedByFile: Some(cb_offset_backed_by_file::<V>), + getNextValidOffset: Some(cb_next_valid_offset::<V>), + getStart: Some(cb_start::<V>), + getLength: Some(cb_length::<V>), + getEntryPoint: Some(cb_entry_point::<V>), + isExecutable: Some(cb_executable::<V>), + getDefaultEndianness: Some(cb_endianness::<V>), + isRelocatable: Some(cb_relocatable::<V>), + getAddressSize: Some(cb_address_size::<V>), + save: Some(cb_save::<V>), + }; + + unsafe { + let res = BNCreateCustomBinaryView( + view_name.as_cstr().as_ptr(), + file.handle, + parent.handle, + &mut bn_obj, + ); + + if res.is_null() { + // TODO not sure when this can even happen, let alone what we're supposed to do about + // it. cb_init isn't normally called until later, and cb_free_object definitely won't + // have been called, so we'd at least be on the hook for freeing that stuff... + // probably. + // + // no idea how to force this to fail so I can test this, so just going to do the + // reasonable thing and panic. + panic!("failed to create custom binary view!"); + } + + (*ctxt).raw_handle = res; + + Ok(CustomView { + handle: Ref::new(BinaryView::from_raw(res)), + _builder: PhantomData, + }) + } + } + + pub fn wrap_existing(self, wrapped_view: Ref<BinaryView>) -> Result<CustomView<'a>> { + Ok(CustomView { + handle: wrapped_view, + _builder: PhantomData, + }) + } +} diff --git a/rust/src/databuffer.rs b/rust/src/databuffer.rs new file mode 100644 index 00000000..d660f570 --- /dev/null +++ b/rust/src/databuffer.rs @@ -0,0 +1,71 @@ +// Copyright 2021 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::*; + +use std::ptr; +use std::slice; + +// TODO : DataBuffers are RefCounted objects, this needs to be changed to only return Refs to DataBuffers + +pub struct DataBuffer(*mut BNDataBuffer); + +impl DataBuffer { + pub(crate) fn from_raw(raw: *mut BNDataBuffer) -> Self { + DataBuffer(raw) + } + + pub fn get_data(&self) -> &[u8] { + if self.0 == ptr::null_mut() { + // TODO : Change the default value and remove this + return &[]; + } + let buffer = unsafe { BNGetDataBufferContents(self.0) }; + if buffer.is_null() { + &[] + } else { + unsafe { slice::from_raw_parts(buffer as *const _, self.len()) } + } + } + + pub fn len(&self) -> usize { + unsafe { BNGetDataBufferLength(self.0) } + } + + // pub fn new(data: ?, len: usize) -> Result<Self> { + // let read_buffer = unsafe { BNCreateDataBuffer(data, len) }; + // if read_buffer.is_null() { + // Err(()) + // } else { + // Ok(DataBuffer::from_raw(read_buffer)) + // } + // } +} + +// TODO : delete this +impl Default for DataBuffer { + fn default() -> Self { + DataBuffer::from_raw(ptr::null_mut()) + } +} + +impl Drop for DataBuffer { + fn drop(&mut self) { + if self.0 != ptr::null_mut() { + unsafe { + BNFreeDataBuffer(self.0); + } + } + } +} diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs new file mode 100644 index 00000000..8dfec753 --- /dev/null +++ b/rust/src/disassembly.rs @@ -0,0 +1,204 @@ +// Copyright 2021 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::*; + +use crate::string::BnString; +use crate::{BN_FULL_CONFIDENCE, BN_INVALID_EXPR}; + +use std::convert::From; +use std::mem; +use std::ptr; + +pub type InstructionTextTokenType = BNInstructionTextTokenType; +pub type InstructionTextTokenContext = BNInstructionTextTokenContext; + +pub struct InstructionTextToken(pub(crate) BNInstructionTextToken); + +impl InstructionTextToken { + pub fn new(type_: InstructionTextTokenType, text: &str, value: u64) -> Self { + let raw_name = BnString::new(text); + + // TODO : Maybe impl Drop for this newtype and perhaps call from_raw for the BnString..I think it's a memory leak otherwise + + InstructionTextToken(BNInstructionTextToken { + type_: type_, + text: raw_name.into_raw(), + value: value, + width: text.chars().count() as u64, + size: 0, + operand: 0xffffffff, + context: InstructionTextTokenContext::NoTokenContext, + confidence: BN_FULL_CONFIDENCE, + address: 0, + typeNames: ptr::null_mut(), + namesCount: 0, + }) + } + + pub fn set_value(&mut self, value: u64) { + self.0.value = value; + } + + pub fn set_context(&mut self, context: InstructionTextTokenContext) { + self.0.context = context; + } +} + +impl Default for InstructionTextToken { + fn default() -> Self { + InstructionTextToken(BNInstructionTextToken { + type_: InstructionTextTokenType::TextToken, + text: ptr::null_mut(), + value: 0, + width: 0, + size: 0, + operand: 0, + context: InstructionTextTokenContext::NoTokenContext, + confidence: BN_FULL_CONFIDENCE, + address: 0, + typeNames: ptr::null_mut(), + namesCount: 0, + }) + } +} + +pub struct DisassemblyTextLine(pub(crate) BNDisassemblyTextLine); + +impl DisassemblyTextLine { + // TODO : this should probably be removed, though it doesn't actually hurt anything + pub fn debug_print(&self) { + let tokens: Vec<InstructionTextToken> = + unsafe { Vec::from_raw_parts(self.0.tokens as *mut _, self.0.count, self.0.count) }; + + for token in &tokens { + let token_string = unsafe { BnString::from_raw(token.0.text) }; + print!("{}", token_string); + token_string.into_raw(); + } + + mem::forget(tokens); + } +} + +impl From<Vec<InstructionTextToken>> for DisassemblyTextLine { + fn from(mut tokens: Vec<InstructionTextToken>) -> Self { + tokens.shrink_to_fit(); + + assert!(tokens.len() == tokens.capacity()); + // let (tokens_pointer, tokens_len, _) = unsafe { tokens.into_raw_parts() }; // Can't use for now...still a rust nighly feature + let tokens_pointer = tokens.as_mut_ptr(); + let tokens_len = tokens.len(); + mem::forget(tokens); + + DisassemblyTextLine(BNDisassemblyTextLine { + addr: 0, + instrIndex: BN_INVALID_EXPR, + tokens: tokens_pointer as *mut _, + count: tokens_len, + highlight: BNHighlightColor { + style: BNHighlightColorStyle::StandardHighlightColor, + color: BNHighlightStandardColor::NoHighlightColor, + mixColor: BNHighlightStandardColor::NoHighlightColor, + mix: 0, + r: 0, + g: 0, + b: 0, + alpha: 0, + }, + tags: ptr::null_mut(), + tagCount: 0, + typeInfo: BNDisassemblyTextLineTypeInfo { + hasTypeInfo: false, + parentType: ptr::null_mut(), + fieldIndex: usize::MAX, + }, + }) + } +} + +impl From<&Vec<&str>> for DisassemblyTextLine { + fn from(string_tokens: &Vec<&str>) -> Self { + let mut tokens: Vec<BNInstructionTextToken> = Vec::with_capacity(string_tokens.len()); + tokens.extend(string_tokens.iter().map(|token| { + InstructionTextToken::new(InstructionTextTokenType::TextToken, token, 0).0 + })); + + assert!(tokens.len() == tokens.capacity()); + // let (tokens_pointer, tokens_len, _) = unsafe { tokens.into_raw_parts() }; // Can't use for now...still a rust nighly feature + let tokens_pointer = tokens.as_mut_ptr(); + let tokens_len = tokens.len(); + mem::forget(tokens); + + DisassemblyTextLine(BNDisassemblyTextLine { + addr: 0, + instrIndex: BN_INVALID_EXPR, + tokens: tokens_pointer as *mut _, + count: tokens_len, + highlight: BNHighlightColor { + style: BNHighlightColorStyle::StandardHighlightColor, + color: BNHighlightStandardColor::NoHighlightColor, + mixColor: BNHighlightStandardColor::NoHighlightColor, + mix: 0, + r: 0, + g: 0, + b: 0, + alpha: 0, + }, + tags: ptr::null_mut(), + tagCount: 0, + typeInfo: BNDisassemblyTextLineTypeInfo { + hasTypeInfo: false, + parentType: ptr::null_mut(), + fieldIndex: usize::MAX, + }, + }) + } +} + +impl Default for DisassemblyTextLine { + fn default() -> Self { + DisassemblyTextLine(BNDisassemblyTextLine { + addr: 0, + instrIndex: BN_INVALID_EXPR, + tokens: ptr::null_mut(), + count: 0, + highlight: BNHighlightColor { + style: BNHighlightColorStyle::StandardHighlightColor, + color: BNHighlightStandardColor::NoHighlightColor, + mixColor: BNHighlightStandardColor::NoHighlightColor, + mix: 0, + r: 0, + g: 0, + b: 0, + alpha: 0, + }, + tags: ptr::null_mut(), + tagCount: 0, + typeInfo: BNDisassemblyTextLineTypeInfo { + hasTypeInfo: false, + parentType: ptr::null_mut(), + fieldIndex: usize::MAX, + }, + }) + } +} + +impl Drop for DisassemblyTextLine { + fn drop(&mut self) { + unsafe { + Vec::from_raw_parts(self.0.tokens, self.0.count, self.0.count); + } + } +} diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index 54279233..bd17b482 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -1,3 +1,16 @@ +// Copyright 2021 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. macro_rules! ffi_wrap { ($n:expr, $b:expr) => {{ @@ -8,6 +21,5 @@ macro_rules! ffi_wrap { error!("ffi callback caught panic: {}", $n); process::abort() }) - }} + }}; } - diff --git a/rust/src/fileaccessor.rs b/rust/src/fileaccessor.rs index e3320be2..e45dec89 100644 --- a/rust/src/fileaccessor.rs +++ b/rust/src/fileaccessor.rs @@ -1,25 +1,37 @@ +// Copyright 2021 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::BNFileAccessor; -use std::io::{Read, Write, Seek, SeekFrom}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::marker::PhantomData; use std::slice; -pub struct FileAccessor<'a> -{ +pub struct FileAccessor<'a> { pub(crate) api_object: BNFileAccessor, _ref: PhantomData<&'a mut ()>, } -impl<'a> FileAccessor<'a> -{ +impl<'a> FileAccessor<'a> { pub fn new<F>(f: &'a mut F) -> Self where - F: 'a + Read + Write + Seek + Sized + F: 'a + Read + Write + Seek + Sized, { use std::os::raw::c_void; extern "C" fn cb_get_length<F>(ctxt: *mut c_void) -> u64 where - F: Read + Write + Seek + Sized + F: Read + Write + Seek + Sized, { let f = unsafe { &mut *(ctxt as *mut F) }; @@ -29,9 +41,14 @@ impl<'a> FileAccessor<'a> } } - extern "C" fn cb_read<F>(ctxt: *mut c_void, dest: *mut c_void, offset: u64, len: usize) -> usize + extern "C" fn cb_read<F>( + ctxt: *mut c_void, + dest: *mut c_void, + offset: u64, + len: usize, + ) -> usize where - F: Read + Write + Seek + Sized + F: Read + Write + Seek + Sized, { let f = unsafe { &mut *(ctxt as *mut F) }; let dest = unsafe { slice::from_raw_parts_mut(dest as *mut u8, len) }; @@ -47,9 +64,14 @@ impl<'a> FileAccessor<'a> } } - extern "C" fn cb_write<F>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize + extern "C" fn cb_write<F>( + ctxt: *mut c_void, + offset: u64, + src: *const c_void, + len: usize, + ) -> usize where - F: Read + Write + Seek + Sized + F: Read + Write + Seek + Sized, { let f = unsafe { &mut *(ctxt as *mut F) }; let src = unsafe { slice::from_raw_parts(src as *const u8, len) }; @@ -75,4 +97,3 @@ impl<'a> FileAccessor<'a> } } } - diff --git a/rust/src/filemetadata.rs b/rust/src/filemetadata.rs index bb09a03f..036b85b1 100644 --- a/rust/src/filemetadata.rs +++ b/rust/src/filemetadata.rs @@ -1,24 +1,40 @@ -use binaryninjacore_sys::{BNFileMetadata, - BNCreateFileMetadata, - BNNewFileReference, - BNFreeFileMetadata, - BNCloseFile, - //BNSetFileMetadataNavigationHandler, - BNIsFileModified, - BNIsAnalysisChanged, - BNMarkFileModified, - BNMarkFileSaved, - BNIsBackedByDatabase, - BNGetFilename, - BNSetFilename, - BNBeginUndoActions, - BNCommitUndoActions, - BNUndo, - BNRedo, - BNGetCurrentView, - BNGetCurrentOffset, - BNNavigate, - BNGetFileViewOfType}; +// Copyright 2021 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::{ + BNBeginUndoActions, + BNCloseFile, + BNCommitUndoActions, + BNCreateFileMetadata, + BNFileMetadata, + BNFreeFileMetadata, + BNGetCurrentOffset, + BNGetCurrentView, + BNGetFileViewOfType, + BNGetFilename, + BNIsAnalysisChanged, + BNIsBackedByDatabase, + //BNSetFileMetadataNavigationHandler, + BNIsFileModified, + BNMarkFileModified, + BNMarkFileSaved, + BNNavigate, + BNNewFileReference, + BNRedo, + BNSetFilename, + BNUndo, +}; use crate::binaryview::BinaryView; @@ -39,12 +55,10 @@ impl FileMetadata { } pub fn new() -> Ref<Self> { - unsafe { - Ref::new( - Self { - handle: BNCreateFileMetadata(), - } - ) + unsafe { + Ref::new(Self { + handle: BNCreateFileMetadata(), + }) } } @@ -55,7 +69,9 @@ impl FileMetadata { } pub fn close(&self) { - unsafe { BNCloseFile(self.handle); } + unsafe { + BNCloseFile(self.handle); + } } pub fn filename(&self) -> BnString { @@ -68,7 +84,9 @@ impl FileMetadata { pub fn set_filename<S: BnStrCompatible>(&self, name: S) { let name = name.as_bytes_with_nul(); - unsafe { BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _); } + unsafe { + BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _); + } } pub fn is_modified(&self) -> bool { @@ -76,7 +94,9 @@ impl FileMetadata { } pub fn mark_modified(&self) { - unsafe { BNMarkFileModified(self.handle); } + unsafe { + BNMarkFileModified(self.handle); + } } pub fn is_analysis_changed(&self) -> bool { @@ -84,7 +104,9 @@ impl FileMetadata { } pub fn mark_saved(&self) { - unsafe { BNMarkFileSaved(self.handle); } + unsafe { + BNMarkFileSaved(self.handle); + } } pub fn is_database_backed(&self) -> bool { @@ -92,25 +114,31 @@ impl FileMetadata { } pub fn begin_undo_actions(&self) { - unsafe { BNBeginUndoActions(self.handle); } + unsafe { + BNBeginUndoActions(self.handle); + } } pub fn commit_undo_actions(&self) { - unsafe { BNCommitUndoActions(self.handle); } + unsafe { + BNCommitUndoActions(self.handle); + } } pub fn undo(&self) { - unsafe { BNUndo(self.handle); } + unsafe { + BNUndo(self.handle); + } } pub fn redo(&self) { - unsafe { BNRedo(self.handle); } + unsafe { + BNRedo(self.handle); + } } pub fn current_view(&self) -> BnString { - unsafe { - BnString::from_raw(BNGetCurrentView(self.handle)) - } + unsafe { BnString::from_raw(BNGetCurrentView(self.handle)) } } pub fn current_offset(&self) -> u64 { @@ -164,11 +192,9 @@ unsafe impl RefCountable for FileMetadata { } } - /* BNCreateDatabase, BNCreateDatabaseWithProgress, BNOpenExistingDatabase, BNOpenExistingDatabaseWithProgress, */ - diff --git a/rust/src/flowgraph.rs b/rust/src/flowgraph.rs new file mode 100644 index 00000000..bd30224e --- /dev/null +++ b/rust/src/flowgraph.rs @@ -0,0 +1,181 @@ +// Copyright 2021 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::*; + +use crate::disassembly::DisassemblyTextLine; + +use crate::rc::*; + +use std::marker::PhantomData; + +pub type BranchType = BNBranchType; +pub type EdgePenStyle = BNEdgePenStyle; +pub type ThemeColor = BNThemeColor; +pub type FlowGraphOption = BNFlowGraphOption; + +#[repr(transparent)] +pub struct EdgeStyle(pub(crate) BNEdgeStyle); + +impl EdgeStyle { + pub fn new(style: EdgePenStyle, width: usize, color: ThemeColor) -> Self { + EdgeStyle(BNEdgeStyle { + style: style, + width: width, + color: color, + }) + } +} + +impl Default for EdgeStyle { + fn default() -> Self { + EdgeStyle(BNEdgeStyle { + style: EdgePenStyle::SolidLine, + width: 0, + color: ThemeColor::AddressColor, + }) + } +} + +#[derive(PartialEq, Eq, Hash)] +pub struct FlowGraphNode<'a> { + pub(crate) handle: *mut BNFlowGraphNode, + _data: PhantomData<&'a ()>, +} + +impl<'a> FlowGraphNode<'a> { + pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraphNode) -> Self { + Self { + handle: raw, + _data: PhantomData, + } + } + + pub fn new(graph: &FlowGraph) -> Self { + unsafe { FlowGraphNode::from_raw(BNCreateFlowGraphNode(graph.as_ref().handle)) } + } + + pub fn set_disassembly_lines(&self, lines: &'a Vec<DisassemblyTextLine>) { + unsafe { + BNSetFlowGraphNodeLines(self.as_ref().handle, lines.as_ptr() as *mut _, lines.len()); + // BNFreeDisassemblyTextLines(lines.as_ptr() as *mut _, lines.len()); // Shouldn't need...would be a double free? + } + } + + pub fn set_lines(&self, lines: Vec<&str>) { + let lines = lines + .iter() + .map(|&line| DisassemblyTextLine::from(&vec![line])) + .collect(); + self.set_disassembly_lines(&lines); + } + + pub fn add_outgoing_edge( + &self, + type_: BranchType, + target: &'a FlowGraphNode, + edge_style: &'a EdgeStyle, + ) { + unsafe { + BNAddFlowGraphNodeOutgoingEdge( + self.as_ref().handle, + type_, + target.as_ref().handle, + edge_style.0, + ) + } + } +} + +unsafe impl<'a> RefCountable for FlowGraphNode<'a> { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewFlowGraphNodeReference(handle.handle), + _data: PhantomData, + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeFlowGraphNode(handle.handle); + } +} + +impl<'a> AsRef<FlowGraphNode<'a>> for FlowGraphNode<'a> { + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a> ToOwned for FlowGraphNode<'a> { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +// TODO : FlowGraph are RefCounted objects, this needs to be changed to only return Refs to FlowGraph + +#[derive(PartialEq, Eq, Hash)] +pub struct FlowGraph { + pub(crate) handle: *mut BNFlowGraph, +} + +impl FlowGraph { + pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraph) -> Self { + Self { handle: raw } + } + + pub fn new() -> Self { + unsafe { FlowGraph::from_raw(BNCreateFlowGraph()) } + } + + pub fn append(&self, node: &FlowGraphNode) -> usize { + unsafe { BNAddFlowGraphNode(self.as_ref().handle, node.handle) } + } + + pub fn set_option(&self, option: FlowGraphOption, value: bool) { + unsafe { BNSetFlowGraphOption(self.as_ref().handle, option, value) } + } + + pub fn is_option_set(&self, option: FlowGraphOption) -> bool { + unsafe { BNIsFlowGraphOptionSet(self.as_ref().handle, option) } + } +} + +unsafe impl RefCountable for FlowGraph { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewFlowGraphReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeFlowGraph(handle.handle); + } +} + +impl AsRef<FlowGraph> for FlowGraph { + fn as_ref(&self) -> &Self { + self + } +} + +impl ToOwned for FlowGraph { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} diff --git a/rust/src/function.rs b/rust/src/function.rs index 9a65f837..ec83fa41 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -1,18 +1,32 @@ +// Copyright 2021 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; use binaryninjacore_sys::*; use crate::architecture::CoreArchitecture; +use crate::basicblock::{BasicBlock, BlockContext}; use crate::binaryview::{BinaryView, BinaryViewExt}; use crate::platform::Platform; use crate::symbol::Symbol; -use crate::basicblock::{BasicBlock, BlockContext}; use crate::types::Type; use crate::llil; -use crate::string::*; use crate::rc::*; +use crate::string::*; pub struct Location { pub arch: Option<CoreArchitecture>, @@ -53,13 +67,16 @@ impl Iterator for NativeBlockIter { if res >= self.end { None } else { - self.bv.get_instruction_len(&self.arch, res).map(|x| { - self.cur += x as u64; - res - }).or_else(|| { - self.cur = self.end; - None - }) + self.bv + .get_instruction_len(&self.arch, res) + .map(|x| { + self.cur += x as u64; + res + }) + .or_else(|| { + self.cur = self.end; + None + }) } } } @@ -107,7 +124,7 @@ impl Function { } pub fn arch(&self) -> CoreArchitecture { - unsafe { + unsafe { let arch = BNGetFunctionArchitecture(self.handle); CoreArchitecture::from_raw(arch) } @@ -142,7 +159,7 @@ impl Function { unsafe { BnString::from_raw(BNGetFunctionComment(self.handle)) } } - pub fn set_comment<S: BnStrCompatible>(&self, comment: S) { + pub fn set_comment<S: BnStrCompatible>(&self, comment: S) { let raw = comment.as_bytes_with_nul(); unsafe { @@ -154,7 +171,7 @@ impl Function { unsafe { BnString::from_raw(BNGetCommentForAddress(self.handle, addr)) } } - pub fn set_comment_at<S: BnStrCompatible>(&self, addr: u64, comment: S) { + pub fn set_comment_at<S: BnStrCompatible>(&self, addr: u64, comment: S) { let raw = comment.as_bytes_with_nul(); unsafe { @@ -172,7 +189,11 @@ impl Function { } } - pub fn basic_block_containing(&self, arch: &CoreArchitecture, addr: u64) -> Option<Ref<BasicBlock<NativeBlock>>> { + pub fn basic_block_containing( + &self, + arch: &CoreArchitecture, + addr: u64, + ) -> Option<Ref<BasicBlock<NativeBlock>>> { unsafe { let block = BNGetFunctionBasicBlockAtAddress(self.handle, arch.0, addr); let context = NativeBlock { _priv: () }; @@ -218,7 +239,13 @@ impl Function { impl fmt::Debug for Function { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "<func '{}' ({}) {:x}>", self.symbol().name(), self.platform().name(), self.start()) + write!( + f, + "<func '{}' ({}) {:x}>", + self.symbol().full_name(), + self.platform().name(), + self.start() + ) } } diff --git a/rust/src/headless.rs b/rust/src/headless.rs index e6b7c51c..f7b9f16d 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -1,15 +1,29 @@ +// Copyright 2021 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::env; +use std::ffi::{CStr, CString, OsStr}; use std::mem; use std::os::raw; -use std::ffi::{OsStr, CString, CStr}; use std::path::PathBuf; #[repr(C)] struct DlInfo { - dli_fname: *const raw::c_char, - dli_fbase: *mut raw::c_void, - dli_sname: *const raw::c_char, - dli_saddr: *mut raw::c_void + dli_fname: *const raw::c_char, + dli_fbase: *mut raw::c_void, + dli_sname: *const raw::c_char, + dli_saddr: *mut raw::c_void, } #[cfg(not(target_os = "windows"))] @@ -20,12 +34,12 @@ fn binja_path() -> PathBuf { return PathBuf::from(p); } - extern { + extern "C" { fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int; } - + unsafe { - let mut info: DlInfo = mem::uninitialized(); + let mut info: DlInfo = mem::zeroed(); if dladdr(BNSetBundledPluginDirectory as *mut _, &mut info) == 0 { panic!("Failed to find libbinaryninjacore path!"); @@ -44,16 +58,14 @@ fn binja_path() -> PathBuf { } } - #[cfg(target_os = "windows")] fn binja_path() -> PathBuf { PathBuf::from(env::var("PROGRAMFILES").unwrap()).join("Vector35\\BinaryNinja\\") } -use binaryninjacore_sys::{BNSetBundledPluginDirectory, - BNInitCorePlugins, - BNInitUserPlugins, - BNInitRepoPlugins}; +use binaryninjacore_sys::{ + BNInitCorePlugins, BNInitRepoPlugins, BNInitUserPlugins, BNSetBundledPluginDirectory, +}; pub fn init() { unsafe { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 68df9948..bdef8368 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,9 +1,28 @@ +// Copyright 2021 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. + +//! # Warning +//! > ⚠️ **These bindings are in a very early beta, only have partial support for the core APIs and are still actively under development. Compatibility _will_ break and conventions _will_ change! They are being used for core Binary Ninja features however, so we expect much of what is already there to be reliable enough to build on, just don't be surprised if your plugins/scripts need to hit a moving target.** + #[macro_use] extern crate log; +pub extern crate binaryninjacore_sys; // For testing functions and stuff +#[cfg(feature = "ui")] +pub extern crate binaryninjaui_sys; // For testing functions and stuff +extern crate libc; #[cfg(feature = "rayon")] extern crate rayon; -extern crate libc; -extern crate binaryninjacore_sys; // TODO // move some options to results @@ -22,34 +41,58 @@ mod ffi; pub mod architecture; pub mod basicblock; pub mod binaryview; -pub mod segment; -pub mod section; -pub mod symbol; pub mod callingconvention; pub mod command; +pub mod custombinaryview; +pub mod databuffer; +pub mod disassembly; pub mod fileaccessor; pub mod filemetadata; +pub mod flowgraph; pub mod function; -pub mod platform; +pub mod headless; pub mod llil; -pub mod types; +pub mod platform; pub mod rc; -pub mod headless; -pub mod string; +pub mod section; +pub mod segment; pub mod settings; +pub mod string; +pub mod symbol; +pub mod types; -pub use binaryninjacore_sys::BNEndianness as Endianness; pub use binaryninjacore_sys::BNBranchType as BranchType; +pub use binaryninjacore_sys::BNEndianness as Endianness; + +// Commented out to suppress unused warnings +// const BN_MAX_INSTRUCTION_LENGTH: u64 = 256; +// const BN_DEFAULT_NSTRUCTION_LENGTH: u64 = 16; +// const BN_DEFAULT_OPCODE_DISPLAY: u64 = 8; +// const BN_MAX_INSTRUCTION_BRANCHES: u64 = 3; +// const BN_MAX_STORED_DATA_LENGTH: u64 = 0x3fffffff; +// const BN_NULL_ID: i64 = -1; +// const BN_INVALID_REGISTER: usize = 0xffffffff; +// const BN_AUTOCOERCE_EXTERN_PTR: u64 = 0xfffffffd; +// const BN_NOCOERCE_EXTERN_PTR: u64 = 0xfffffffe; +// const BN_INVALID_OPERAND: u64 = 0xffffffff; +// const BN_MAX_STRING_LENGTH: u64 = 128; +// const BN_MAX_VARIABLE_OFFSET: u64 = 0x7fffffffff; +// const BN_MAX_VARIABLE_INDEX: u64 = 0xfffff; +// const BN_MINIMUM_CONFIDENCE: u8 = 1; +// const BN_HEURISTIC_CONFIDENCE: u8 = 192; + +const BN_FULL_CONFIDENCE: u8 = 255; +const BN_INVALID_EXPR: usize = usize::MAX; pub mod logger { - use std::os::raw::{c_void, c_char}; + use std::os::raw::{c_char, c_void}; use log; use crate::string::BnStr; - use binaryninjacore_sys::{BNLogListener, BNUpdateLogListeners}; pub use binaryninjacore_sys::BNLogLevel as Level; + use binaryninjacore_sys::{BNLogListener, BNUpdateLogListeners}; struct Logger; static LOGGER: Logger = Logger; @@ -60,21 +103,22 @@ pub mod logger { } fn log(&self, record: &log::Record) { - use binaryninjacore_sys::BNLog; - use std::ffi::CString; use self::Level::*; + use binaryninjacore_sys::BNLog; use log::Level; + use std::ffi::CString; let level = match record.level() { Level::Error => ErrorLog, Level::Warn => WarningLog, Level::Info => InfoLog, - Level::Debug | - Level::Trace => DebugLog, + Level::Debug | Level::Trace => DebugLog, }; if let Ok(msg) = CString::new(format!("{}", record.args())) { - unsafe { BNLog(level, msg.as_ptr()); } + unsafe { + BNLog(level, msg.as_ptr()); + } }; } @@ -134,9 +178,7 @@ pub mod logger { BNUpdateLogListeners(); } - LogGuard { - ctxt: raw, - } + LogGuard { ctxt: raw } } extern "C" fn cb_log<L>(ctxt: *mut c_void, level: Level, msg: *const c_char) @@ -158,7 +200,7 @@ pub mod logger { listener.close(); }) } - + extern "C" fn cb_level<L>(ctxt: *mut c_void) -> Level where L: LogListener, @@ -169,3 +211,7 @@ pub mod logger { }) } } + +pub fn version() -> string::BnString { + unsafe { string::BnString::from_raw(binaryninjacore_sys::BNGetVersionString()) } +} diff --git a/rust/src/llil/block.rs b/rust/src/llil/block.rs index 543ab670..63e93338 100644 --- a/rust/src/llil/block.rs +++ b/rust/src/llil/block.rs @@ -1,3 +1,17 @@ +// Copyright 2021 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; @@ -31,8 +45,6 @@ where } } - - pub struct Block<'func, A, M, F> where A: 'func + Architecture, @@ -72,7 +84,7 @@ where fn iter(&self, block: &BasicBlock<Self>) -> BlockIter<'func, A, M, F> { BlockIter { function: self.function, - range: block.raw_start() .. block.raw_end(), + range: block.raw_start()..block.raw_end(), } } } @@ -84,8 +96,8 @@ where F: FunctionForm, { fn clone(&self) -> Self { - Block { function: self.function } + Block { + function: self.function, + } } } - - diff --git a/rust/src/llil/expression.rs b/rust/src/llil/expression.rs index 1e1edda4..4cf2cad5 100644 --- a/rust/src/llil/expression.rs +++ b/rust/src/llil/expression.rs @@ -1,12 +1,26 @@ +// Copyright 2021 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::marker::PhantomData; use std::fmt; +use std::marker::PhantomData; -use super::*; use super::operation; use super::operation::Operation; +use super::*; use crate::architecture::Architecture; use crate::architecture::RegisterInfo; @@ -61,8 +75,10 @@ where } } -fn common_info<'func, A, M, F>(function: &'func Function<A, M, F>, op: BNLowLevelILInstruction) - -> ExprInfo<'func, A, M, F> +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, @@ -79,7 +95,7 @@ where 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_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)), @@ -132,8 +148,10 @@ where _ => { #[cfg(debug_assertions)] { - error!("Got unexpected operation {:?} in value expr at 0x{:x}", - op.operation, op.address); + error!( + "Got unexpected operation {:?} in value expr at 0x{:x}", + op.operation, op.address + ); } ExprInfo::Undef(Operation::new(function, op)) @@ -151,8 +169,7 @@ macro_rules! visit { } } -fn common_visit<'func, A, M, F, CB>(info: &ExprInfo<'func, A, M, F>, f: &mut CB) - -> VisitorAction +fn common_visit<'func, A, M, F, CB>(info: &ExprInfo<'func, A, M, F>, f: &mut CB) -> VisitorAction where A: 'func + Architecture, M: FunctionMutability, @@ -162,60 +179,33 @@ where 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) => { + 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) => { visit!(f, &op.left()); visit!(f, &op.right()); } - Adc(ref op) | - Sbb(ref op) | - Rlc(ref op) | - Rrc(ref op) => { + 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) => { + 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) => { visit!(f, &op.left()); visit!(f, &op.right()); } - DivuDp(ref op) | - DivsDp(ref op) | - ModuDp(ref op) | - ModsDp(ref op) => { + 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) => { + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) => { visit!(f, &op.operand()); } @@ -235,7 +225,10 @@ where M: FunctionMutability, V: NonSSAVariant, { - pub(crate) unsafe fn info_from_op(&self, op: BNLowLevelILInstruction) -> ExprInfo<'func, A, M, NonSSA<V>> { + pub(crate) unsafe fn info_from_op( + &self, + op: BNLowLevelILInstruction, + ) -> ExprInfo<'func, A, M, NonSSA<V>> { use binaryninjacore_sys::BNLowLevelILOperation::*; match op.operation { @@ -266,7 +259,7 @@ where let info = self.info(); match f(self, &info) { - VisitorAction::Descend => {}, + VisitorAction::Descend => {} action => return action, }; @@ -287,13 +280,15 @@ where A: 'func + Architecture, M: FunctionMutability, { - pub(crate) unsafe fn info_from_op(&self, op: BNLowLevelILInstruction) -> ExprInfo<'func, A, M, SSA> { + 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_SSA | LLIL_REG_SSA_PARTIAL => ExprInfo::Reg(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), @@ -316,7 +311,7 @@ where let info = self.info(); match f(self, &info) { - VisitorAction::Descend => {}, + VisitorAction::Descend => {} action => return action, }; @@ -341,8 +336,6 @@ where // TODO possible values } - - pub enum ExprInfo<'func, A, M, F> where A: 'func + Architecture, @@ -362,7 +355,7 @@ where 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>), + 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>), @@ -409,11 +402,9 @@ where 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>), // TODO ADD_OVERFLOW - Unimpl(Operation<'func, A, M, F, operation::NoArgs>), UnimplMem(Operation<'func, A, M, F, operation::UnimplMem>), @@ -427,25 +418,21 @@ where 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, + Undef(..) | Unimpl(..) => None, - FlagCond(..) | FlagGroup(..) | - CmpE(..) | CmpNe(..) | - CmpSlt(..) | CmpUlt(..) | - CmpSle(..) | CmpUle(..) | - CmpSge(..) | CmpUge(..) | - CmpSgt(..) | CmpUgt(..) => Some(0), + 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 } } @@ -455,13 +442,13 @@ where } /// 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, + (&Reg(..), &Reg(..)) => true, _ => self.raw_struct().operation == other.raw_struct().operation, } } @@ -470,11 +457,9 @@ where 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) => Some(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) => Some(op), _ => None, } } @@ -483,47 +468,32 @@ where 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) => Some(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) => Some(op), _ => None, } } - pub fn as_binary_op_carry(&self) -> Option<&Operation<'func, A, M, F, operation::BinaryOpCarry>> { + 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), + 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>> { + 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), + DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => Some(op), _ => None, } } @@ -532,12 +502,8 @@ where use self::ExprInfo::*; match *self { - Neg(ref op) | - Not(ref op) | - Sx(ref op) | - Zx(ref op) | - LowPart(ref op) | - BoolToInt(ref op) => Some(op), + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) => Some(op), _ => None, } } @@ -553,11 +519,9 @@ where 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) => &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) => &op.op, Load(ref op) => &op.op, @@ -569,46 +533,21 @@ where FlagBit(ref op) => &op.op, - Const(ref op) | - ConstPtr(ref op) => &op.op, + Const(ref op) | ConstPtr(ref op) => &op.op, - Adc(ref op) | - Sbb(ref op) | - Rlc(ref op) | - Rrc(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) => &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) => &op.op, - DivuDp(ref op) | - DivsDp(ref op) | - ModuDp(ref op) | - ModsDp(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) => &op.op, + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) => &op.op, UnimplMem(ref op) => &op.op, - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO } } @@ -618,23 +557,20 @@ 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, + Undef(ref _op) => None, - Unimpl(ref op) => None, + Unimpl(ref _op) => None, - FlagCond(ref op) => None, - FlagGroup(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) => 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) => None, Load(ref op) => op.flag_write(), @@ -646,46 +582,21 @@ where FlagBit(ref op) => op.flag_write(), - Const(ref op) | - ConstPtr(ref op) => op.flag_write(), + Const(ref op) | ConstPtr(ref op) => op.flag_write(), - Adc(ref op) | - Sbb(ref op) | - Rlc(ref op) | - Rrc(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) => 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) => op.flag_write(), - DivuDp(ref op) | - DivsDp(ref op) | - ModuDp(ref op) | - ModsDp(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) => op.flag_write(), + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) => op.flag_write(), UnimplMem(ref op) => op.flag_write(), - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO } } @@ -708,15 +619,20 @@ where 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) => { + 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) => { let left = op.left(); let right = op.right(); - write!(f, "{:?}({}, {:?}, {:?})", op.op.operation, op.size(), left, right) + write!( + f, + "{:?}({}, {:?}, {:?})", + op.op.operation, + op.size(), + left, + right + ) } Load(ref op) => { @@ -735,7 +651,7 @@ where let size = match reg { Register::Temp(_) => Some(size), Register::ArchReg(ref r) if r.info().size() != size => Some(size), - _ => None + _ => None, }; match size { @@ -748,68 +664,67 @@ where FlagBit(ref _op) => write!(f, "flag_bit"), // TODO - Const(ref op) | - ConstPtr(ref op) => write!(f, "0x{:x}", op.value()), + Const(ref op) | ConstPtr(ref op) => write!(f, "0x{:x}", op.value()), - Adc(ref op) | - Sbb(ref op) | - Rlc(ref op) | - Rrc(ref op) => { + 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) + 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) => { + 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) => { let left = op.left(); let right = op.right(); - write!(f, "{:?}({}, {:?}, {:?})", - op.op.operation, op.size(), left, right) + write!( + f, + "{:?}({}, {:?}, {:?})", + op.op.operation, + op.size(), + left, + right + ) } - DivuDp(ref op) | - DivsDp(ref op) | - ModuDp(ref op) | - ModsDp(ref op) => { + 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) + 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) => { - write!(f, "{:?}({}, {:?})", op.op.operation, op.size(), op.operand()) - } + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(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 index ac50e72c..adc39f13 100644 --- a/rust/src/llil/function.rs +++ b/rust/src/llil/function.rs @@ -1,6 +1,20 @@ +// Copyright 2021 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 binaryninjacore_sys::BNFreeLowLevelILFunction; use std::borrow::Borrow; use std::marker::PhantomData; @@ -19,7 +33,6 @@ pub trait FunctionMutability: 'static {} impl FunctionMutability for Mutable {} impl FunctionMutability for Finalized {} - #[derive(Copy, Clone, Debug)] pub struct LiftedNonSSA; #[derive(Copy, Clone, Debug)] @@ -38,7 +51,6 @@ 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, @@ -68,7 +80,7 @@ impl<'func, A, M, F> Function<A, M, F> where A: 'func + Architecture, M: FunctionMutability, - F: FunctionForm + F: FunctionForm, { pub(crate) unsafe fn from_raw(borrower: A::Handle, handle: *mut BNLowLevelILFunction) -> Self { debug_assert!(!handle.is_null()); @@ -87,8 +99,8 @@ where } pub fn instruction_at<L: Into<Location>>(&self, loc: L) -> Option<Instruction<A, M, F>> { - use binaryninjacore_sys::BNLowLevelILGetInstructionStart; 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()); @@ -112,7 +124,7 @@ where use binaryninjacore_sys::BNGetLowLevelILInstructionCount; if instr_idx >= BNGetLowLevelILInstructionCount(self.handle) { panic!("instruction index {} out of bounds", instr_idx); - } + } Instruction { function: self, @@ -127,7 +139,6 @@ where BNGetLowLevelILInstructionCount(self.handle) } } - } // LLIL basic blocks are not available until the function object @@ -136,7 +147,7 @@ where impl<'func, A, F> Function<A, Finalized, F> where A: 'func + Architecture, - F: FunctionForm + F: FunctionForm, { pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelBlock<A, Finalized, F>>> { use binaryninjacore_sys::BNGetLowLevelILBasicBlockList; @@ -155,7 +166,7 @@ impl<'func, A, M, F> ToOwned for Function<A, M, F> where A: 'func + Architecture, M: FunctionMutability, - F: FunctionForm + F: FunctionForm, { type Owned = Ref<Self>; @@ -164,12 +175,11 @@ where } } - unsafe impl<'func, A, M, F> RefCountable for Function<A, M, F> where A: 'func + Architecture, M: FunctionMutability, - F: FunctionForm + F: FunctionForm, { unsafe fn inc_ref(handle: &Self) -> Ref<Self> { Ref::new(Self { diff --git a/rust/src/llil/instruction.rs b/rust/src/llil/instruction.rs index 4d1554df..109e5ea7 100644 --- a/rust/src/llil/instruction.rs +++ b/rust/src/llil/instruction.rs @@ -1,12 +1,26 @@ +// Copyright 2021 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 std::marker::PhantomData; -use super::*; use super::operation; use super::operation::Operation; +use super::*; use crate::architecture::Architecture; @@ -20,8 +34,10 @@ where 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>> +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, @@ -54,8 +70,7 @@ macro_rules! visit { } } -fn common_visit<'func, A, M, F, CB>(info: &InstrInfo<'func, A, M, F>, f: &mut CB) - -> VisitorAction +fn common_visit<'func, A, M, F, CB>(info: &InstrInfo<'func, A, M, F>, f: &mut CB) -> VisitorAction where A: 'func + Architecture, M: FunctionMutability, @@ -70,7 +85,7 @@ where Ret(ref op) => visit!(f, &op.target()), If(ref op) => visit!(f, &op.condition()), Value(ref e, _) => visit!(f, e), - _ => {}, + _ => {} }; VisitorAction::Sibling @@ -85,7 +100,8 @@ where 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 expr_idx = + unsafe { BNGetLowLevelILIndexForInstruction(self.function.handle, self.instr_idx) }; let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, expr_idx) }; match op.operation { @@ -94,8 +110,9 @@ where 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_CALL | LLIL_CALL_STACK_ADJUST => { + InstrInfo::Call(Operation::new(self.function, op)) + } LLIL_SYSCALL => InstrInfo::Syscall(Operation::new(self.function, op)), _ => { common_info(self.function, op).unwrap_or_else(|| { @@ -118,7 +135,10 @@ where 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, + F: FnMut( + &Expression<'func, A, M, NonSSA<V>, ValueExpr>, + &ExprInfo<'func, A, M, NonSSA<V>>, + ) -> VisitorAction, { use self::InstrInfo::*; let info = self.info(); @@ -171,5 +191,8 @@ where 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>), + 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 index e50eaaf1..90c5b46a 100644 --- a/rust/src/llil/lifting.rs +++ b/rust/src/llil/lifting.rs @@ -1,23 +1,43 @@ +// Copyright 2021 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::Register as ArchReg; -use crate::architecture::{FlagWrite, Flag, FlagClass, FlagGroup, FlagRole, FlagCondition}; use crate::architecture::Architecture; - +use crate::architecture::Register as ArchReg; +use crate::architecture::{Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite}; 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>; + 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>; +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; @@ -40,7 +60,7 @@ impl<R: ArchReg> RegisterOrConstant<R> { constant: true, reg: 0, value: value, - } + }, } } } @@ -90,30 +110,57 @@ pub enum FlagWriteOp<R: ArchReg> { 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>), + 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> + 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>, + A: Architecture<Register = R>, + R: ArchReg<InfoType = A::RegisterInfo>, { - use binaryninjacore_sys::BNLowLevelILOperation::*; use self::FlagWriteOp::*; + use binaryninjacore_sys::BNLowLevelILOperation::*; - fn build_op<A, R>(arch: &A, size: usize, operand: &BNRegisterOrConstant) -> RegisterOrConstant<R> + fn build_op<A, R>( + arch: &A, + size: usize, + operand: &BNRegisterOrConstant, + ) -> RegisterOrConstant<R> where - A: Architecture<Register=R>, - R: ArchReg<InfoType=A::RegisterInfo>, + A: Architecture<Register = R>, + R: ArchReg<InfoType = A::RegisterInfo>, { if operand.constant { RegisterOrConstant::Constant(size, operand.value) @@ -182,15 +229,15 @@ impl<R: ArchReg> FlagWriteOp<R> { (3, LLIL_RLC) => op!(Rlc, 0, 1, 2), (3, LLIL_RRC) => op!(Rrc, 0, 1, 2), - (0, LLIL_POP) => op!(Pop, ), + (0, LLIL_POP) => op!(Pop,), _ => return None, }) } pub(crate) fn size_and_op(&self) -> (usize, BNLowLevelILOperation) { - use binaryninjacore_sys::BNLowLevelILOperation::*; use self::FlagWriteOp::*; + use binaryninjacore_sys::BNLowLevelILOperation::*; match *self { SetReg(size, ..) => (size, LLIL_SET_REG), @@ -252,54 +299,54 @@ impl<R: ArchReg> FlagWriteOp<R> { 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) => { + 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) => { + 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) => { + 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(); @@ -311,19 +358,29 @@ impl<R: ArchReg> FlagWriteOp<R> { } } - -pub fn get_default_flag_write_llil<'func, A>(arch: &A, role: FlagRole, op: FlagWriteOp<A::Register>, il: &'func Lifter<A>) - -> LiftedExpr<'func, A> +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 + 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) + BNGetDefaultArchitectureFlagWriteLowLevelIL( + arch.as_ref().0, + operation, + size, + role, + operands.as_ptr() as *mut _, + count, + il.handle, + ) }; Expression { @@ -333,10 +390,14 @@ where } } -pub fn get_default_flag_cond_llil<'func, A>(arch: &A, cond: FlagCondition, class: Option<A::FlagClass>, il: &'func Lifter<A>) - -> LiftedExpr<'func, A> +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 + A: 'func + Architecture, { use binaryninjacore_sys::BNGetDefaultArchitectureFlagConditionLowLevelIL; @@ -344,7 +405,8 @@ where let class_id = class.map(|c| c.id()).unwrap_or(0); unsafe { - let expr_idx = BNGetDefaultArchitectureFlagConditionLowLevelIL(handle.0, cond, class_id, il.handle); + let expr_idx = + BNGetDefaultArchitectureFlagConditionLowLevelIL(handle.0, cond, class_id, il.handle); Expression { function: il, @@ -402,13 +464,15 @@ 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>> +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> - { + 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)), @@ -417,11 +481,14 @@ impl<'a, R: ArchReg, A: 'a + Architecture> Liftable<'a, A> for Register<R> } impl<'a, R: ArchReg, A: 'a + Architecture> LiftableWithSize<'a, A> for Register<R> - where R: LiftableWithSize<'a, A> + Into<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> - { + 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)), @@ -429,15 +496,16 @@ impl<'a, R: ArchReg, A: 'a + Architecture> LiftableWithSize<'a, A> for Register< } } - impl<'a, R: ArchReg, A: 'a + Architecture> Liftable<'a, A> for RegisterOrConstant<R> - where R: LiftableWithSize<'a, A, Result=ValueExpr> + Into<Register<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> - { + 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), @@ -446,11 +514,14 @@ impl<'a, R: ArchReg, A: 'a + Architecture> Liftable<'a, A> for RegisterOrConstan } impl<'a, R: ArchReg, A: 'a + Architecture> LiftableWithSize<'a, A> for RegisterOrConstant<R> - where R: LiftableWithSize<'a, A> + Into<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> - { + 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), @@ -459,7 +530,6 @@ impl<'a, R: ArchReg, A: 'a + Architecture> LiftableWithSize<'a, A> for RegisterO } } - impl<'a, A, R> Liftable<'a, A> for Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R> where A: 'a + Architecture, @@ -467,24 +537,33 @@ where { type Result = R; - fn lift(il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, expr: Self) - -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> - { + 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> - { +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); + warn!( + "il @ {:x} attempted to lift {} byte expression as {} bytes", + il.current_address(), + expr_size, + _size + ); } } } @@ -493,7 +572,6 @@ impl<'a, A: 'a + Architecture> LiftableWithSize<'a, A> for Expression<'a, A, Mut } } - impl<'func, A, R> Expression<'func, A, Mutable, NonSSA<LiftedNonSSA>, R> where A: 'func + Architecture, @@ -502,9 +580,7 @@ where pub fn with_source_operand(self, op: u32) -> Self { use binaryninjacore_sys::BNLowLevelILSetExprSourceOperand; - unsafe { - BNLowLevelILSetExprSourceOperand(self.function.handle, self.expr_idx, op) - } + unsafe { BNLowLevelILSetExprSourceOperand(self.function.handle, self.expr_idx, op) } self } @@ -515,7 +591,6 @@ where } } - use binaryninjacore_sys::BNLowLevelILOperation; pub struct ExpressionBuilder<'func, A, R> where @@ -548,7 +623,10 @@ where self.into() } - pub fn with_source_operand(self, op: u32) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R> { + pub fn with_source_operand( + self, + op: u32, + ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R> { let expr = self.into_expr(); expr.with_source_operand(op) } @@ -561,7 +639,8 @@ where } } -impl<'a, A, R> Into<Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R>> for ExpressionBuilder<'a, A, R> +impl<'a, A, R> Into<Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, R>> + for ExpressionBuilder<'a, A, R> where A: 'a + Architecture, R: ExpressionResultType, @@ -570,9 +649,16 @@ where 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) + BNLowLevelILAddExpr( + self.function.handle, + self.op, + self.size, + self.flags, + self.op1, + self.op2, + self.op3, + self.op4, + ) }; Expression { @@ -590,9 +676,10 @@ where { type Result = R; - fn lift(il: &'a Function<A, Mutable, NonSSA<LiftedNonSSA>>, expr: Self) - -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, Self::Result> - { + 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.into() @@ -603,34 +690,36 @@ 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> - { + 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); + 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::BNLowLevelILOperation::$op; use binaryninjacore_sys::BNLowLevelILAddExpr; + use binaryninjacore_sys::BNLowLevelILOperation::$op; - let expr_idx = unsafe { - BNLowLevelILAddExpr(self.handle, $op, - 0, 0, 0, 0, 0, 0) - }; + let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, $op, 0, 0, 0, 0, 0, 0) }; Expression { function: self, @@ -638,13 +727,12 @@ macro_rules! no_arg_lifter { _ty: PhantomData, } } - } + }; } macro_rules! sized_no_arg_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name(&self, size: usize) -> ExpressionBuilder<A, $result> - { + pub fn $name(&self, size: usize) -> ExpressionBuilder<A, $result> { use binaryninjacore_sys::BNLowLevelILOperation::$op; ExpressionBuilder { @@ -659,24 +747,25 @@ macro_rules! sized_no_arg_lifter { _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> + pub fn $name<'a, E>( + &'a self, + expr: E, + ) -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, $result> where - E: Liftable<'a, A, Result=ValueExpr> + E: Liftable<'a, A, Result = ValueExpr>, { - use binaryninjacore_sys::BNLowLevelILOperation::$op; 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) + BNLowLevelILAddExpr(self.handle, $op, 0, 0, expr.expr_idx as u64, 0, 0, 0) }; Expression { @@ -685,15 +774,14 @@ macro_rules! unsized_unary_op_lifter { _ty: PhantomData, } } - } + }; } 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> + pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, A, $result> where - E: LiftableWithSize<'a, A> + E: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -711,15 +799,14 @@ macro_rules! sized_unary_op_lifter { _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> + pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, A, $result> where - E: LiftableWithSize<'a, A> + E: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -737,16 +824,20 @@ macro_rules! size_changing_unary_op_lifter { _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> + 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> + R: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -765,13 +856,18 @@ macro_rules! binary_op_lifter { _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> + 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>, @@ -795,21 +891,21 @@ macro_rules! binary_op_carry_lifter { _ty: PhantomData, } } - } + }; } impl<A> Function<A, Mutable, NonSSA<LiftedNonSSA>> where A: Architecture, { - pub fn expression<'a, E: Liftable<'a, A>>(&'a self, expr: E) - -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, E::Result> - { + 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) - { + pub fn instruction<'a, E: Liftable<'a, A>>(&'a self, expr: E) { let expr = self.expression(expr); unsafe { @@ -818,35 +914,35 @@ where } } - pub unsafe fn replace_expression<'a, E: Liftable<'a, A>>( &'a self, replaced_expr_index: usize, - replacement: E) - { - unsafe { - use binaryninjacore_sys::BNReplaceLowLevelILExpr; - use binaryninjacore_sys::BNGetLowLevelILExprCount; - - if replaced_expr_index >= BNGetLowLevelILExprCount(self.handle) { - panic!("bad expr idx used: {} exceeds function bounds", replaced_expr_index); - } + replacement: E, + ) { + use binaryninjacore_sys::BNGetLowLevelILExprCount; + use binaryninjacore_sys::BNReplaceLowLevelILExpr; - let expr = self.expression(replacement); - BNReplaceLowLevelILExpr(self.handle, replaced_expr_index, expr.expr_idx); + 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::BNLowLevelILOperation::LLIL_CONST; + 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) - }; + let expr_idx = + unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST, size, 0, val, 0, 0, 0) }; Expression { function: self, @@ -855,16 +951,16 @@ where } } - pub fn const_ptr_sized(&self, size: usize, val: u64) - -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST_PTR; + 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) - }; + let expr_idx = + unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST_PTR, size, 0, val, 0, 0, 0) }; Expression { function: self, @@ -873,22 +969,15 @@ where } } - pub fn const_ptr(&self, val: u64) - -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { + 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::BNLowLevelILOperation::LLIL_TRAP; + 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) - }; + let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_TRAP, 0, 0, val, 0, 0, 0) }; Expression { function: self, @@ -910,19 +999,26 @@ where 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>, + 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 _) + BNLowLevelILIf( + self.handle, + cond.expr_idx as u64, + &t.0 as *const _ as *mut _, + &f.0 as *const _ as *mut _, + ) }; Expression { @@ -932,14 +1028,13 @@ where } } - pub fn goto<'a: 'b, 'b>(&'a self, l: &'b Label) - -> Expression<'a, A, Mutable, NonSSA<LiftedNonSSA>, VoidExpr> - { + 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 _) - }; + let expr_idx = unsafe { BNLowLevelILGoto(self.handle, &l.0 as *const _ as *mut _) }; Expression { function: self, @@ -948,11 +1043,13 @@ where } } - pub fn reg<R: Into<Register<A::Register>>>(&self, size: usize, reg: R) - -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG; + 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() { @@ -960,10 +1057,8 @@ where Register::Temp(r) => 0x8000_0000 | r, }; - let expr_idx = unsafe { - BNLowLevelILAddExpr(self.handle, LLIL_REG, size, 0, - reg as u64, 0, 0, 0) - }; + let expr_idx = + unsafe { BNLowLevelILAddExpr(self.handle, LLIL_REG, size, 0, reg as u64, 0, 0, 0) }; Expression { function: self, @@ -972,11 +1067,15 @@ where } } - pub fn set_reg<'a, R, E>(&'a self, size: usize, dest_reg: R, expr: E) - -> ExpressionBuilder<'a, A, VoidExpr> + 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> + E: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG; @@ -1001,12 +1100,17 @@ where } } - 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> + 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> + E: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG_SPLIT; @@ -1037,17 +1141,13 @@ where } } - pub fn flag(&self, flag: A::Flag) - -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG; + 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) - }; + let expr_idx = + unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG, 0, 0, flag.id() as u64, 0, 0, 0) }; Expression { function: self, @@ -1056,17 +1156,16 @@ where } } - pub fn flag_cond(&self, cond: FlagCondition) - -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_COND; + 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) - }; + let expr_idx = + unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG_COND, 0, 0, cond as u64, 0, 0, 0) }; Expression { function: self, @@ -1075,16 +1174,25 @@ where } } - pub fn flag_group(&self, group: A::FlagGroup) - -> Expression<A, Mutable, NonSSA<LiftedNonSSA>, ValueExpr> - { - use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_GROUP; + 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) + BNLowLevelILAddExpr( + self.handle, + LLIL_FLAG_GROUP, + 0, + 0, + group.id() as u64, + 0, + 0, + 0, + ) }; Expression { @@ -1094,10 +1202,13 @@ where } } - pub fn set_flag<'a, E>(&'a self, dest_flag: A::Flag, expr: E) - -> ExpressionBuilder<'a, A, VoidExpr> + pub fn set_flag<'a, E>( + &'a self, + dest_flag: A::Flag, + expr: E, + ) -> ExpressionBuilder<'a, A, VoidExpr> where - E: LiftableWithSize<'a, A> + E: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_FLAG; @@ -1123,10 +1234,9 @@ where FlagBit(usize, Flag<A>, u64), */ - pub fn load<'a, E>(&'a self, size: usize, source_mem: E) - -> ExpressionBuilder<'a, A, ValueExpr> + pub fn load<'a, E>(&'a self, size: usize, source_mem: E) -> ExpressionBuilder<'a, A, ValueExpr> where - E: Liftable<'a, A, Result=ValueExpr> + E: Liftable<'a, A, Result = ValueExpr>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_LOAD; @@ -1145,11 +1255,15 @@ where } } - pub fn store<'a, D, V>(&'a self, size: usize, dest_mem: D, value: V) - -> ExpressionBuilder<'a, A, VoidExpr> + 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> + D: Liftable<'a, A, Result = ValueExpr>, + V: LiftableWithSize<'a, A>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_STORE; @@ -1206,7 +1320,6 @@ where 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>), @@ -1233,9 +1346,7 @@ where pub fn current_address(&self) -> u64 { use binaryninjacore_sys::BNLowLevelILGetCurrentAddress; - unsafe { - BNLowLevelILGetCurrentAddress(self.handle) - } + unsafe { BNLowLevelILGetCurrentAddress(self.handle) } } pub fn set_current_address<L: Into<Location>>(&self, loc: L) { @@ -1244,7 +1355,9 @@ where let loc: Location = loc.into(); let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref()); - unsafe { BNLowLevelILSetCurrentAddress(self.handle, arch.0, loc.addr); } + unsafe { + BNLowLevelILSetCurrentAddress(self.handle, arch.0, loc.addr); + } } pub fn label_for_address<L: Into<Location>>(&self, loc: L) -> Option<&Label> { @@ -1253,9 +1366,7 @@ where 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) - }; + let res = unsafe { BNGetLowLevelILLabelForAddress(self.handle, arch.0, loc.addr) }; if res.is_null() { None @@ -1282,11 +1393,10 @@ impl Label { use binaryninjacore_sys::BNLowLevelILInitLabel; unsafe { - let mut res = Label(mem::uninitialized()); + // 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 } } } - - diff --git a/rust/src/llil/mod.rs b/rust/src/llil/mod.rs index c3b1b350..198d8373 100644 --- a/rust/src/llil/mod.rs +++ b/rust/src/llil/mod.rs @@ -1,28 +1,44 @@ +// Copyright 2021 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 +// 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::Register as ArchReg; use crate::architecture::Architecture; +use crate::architecture::Register as ArchReg; use crate::function::Location; +mod block; +mod expression; mod function; mod instruction; -mod expression; mod lifting; -mod block; pub mod operation; +pub use self::expression::*; pub use self::function::*; pub use self::instruction::*; -pub use self::expression::*; -pub use self::lifting::{Liftable, LiftableWithSize, Label, ExpressionBuilder, FlagWriteOp, RegisterOrConstant}; -pub use self::lifting::get_default_flag_write_llil; 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; @@ -60,14 +76,13 @@ impl<R: ArchReg> fmt::Debug for Register<R> { #[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 + 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 + SSARegister::Full(_, ver) | SSARegister::Partial(_, ver, _) => ver, } } } @@ -77,4 +92,3 @@ pub enum VisitorAction { Sibling, Halt, } - diff --git a/rust/src/llil/operation.rs b/rust/src/llil/operation.rs index 81d72d57..55d384e9 100644 --- a/rust/src/llil/operation.rs +++ b/rust/src/llil/operation.rs @@ -1,3 +1,17 @@ +// Copyright 2021 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::BNLowLevelILInstruction; use std::marker::PhantomData; @@ -46,7 +60,7 @@ where pub fn flag_write(&self) -> Option<A::FlagWrite> { match self.op.flags { 0 => None, - id => self.function.arch().flag_write_from_id(id) + id => self.function.arch().flag_write_from_id(id), } } } @@ -54,8 +68,6 @@ where // LLIL_NOP, LLIL_NORET, LLIL_BP, LLIL_UNDEF, LLIL_UNIMPL pub struct NoArgs; - - // LLIL_POP pub struct Pop; @@ -70,15 +82,9 @@ where } } - - - // LLIL_SYSCALL, LLIL_SYSCALL_SSA pub struct Syscall; - - - // LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA pub struct SetReg; @@ -98,14 +104,18 @@ where 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); + 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) - }) + Register::Temp(0) + }) } } @@ -118,7 +128,6 @@ where } } - // LLIL_SET_REG_SPLIT, LLIL_SET_REG_SPLIT_SSA pub struct SetRegSplit; @@ -138,14 +147,18 @@ where 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); + 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) - }) + Register::Temp(0) + }) } } @@ -155,14 +168,18 @@ where 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); + 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) - }) + Register::Temp(0) + }) } } @@ -175,9 +192,6 @@ where } } - - - // LLIL_SET_FLAG, LLIL_SET_FLAG_SSA pub struct SetFlag; @@ -196,7 +210,6 @@ where } } - // LLIL_LOAD, LLIL_LOAD_SSA pub struct Load; @@ -219,8 +232,6 @@ where } } - - // LLIL_STORE, LLIL_STORE_SSA pub struct Store; @@ -251,8 +262,6 @@ where } } - - // LLIL_REG, LLIL_REG_SSA, LLIL_REG_SSA_PARTIAL pub struct Reg; @@ -272,31 +281,28 @@ where 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); + 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) - }) + 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; @@ -315,8 +321,6 @@ where } } - - // LLIL_JUMP_TO pub struct JumpTo; @@ -336,8 +340,6 @@ where // TODO target list } - - // LLIL_CALL, LLIL_CALL_SSA pub struct Call; @@ -366,8 +368,6 @@ where } } - - // LLIL_RET pub struct Ret; @@ -386,8 +386,6 @@ where } } - - // LLIL_IF pub struct If; @@ -420,8 +418,6 @@ where } } - - // LLIL_GOTO pub struct Goto; @@ -439,13 +435,9 @@ where } } - - // LLIL_FLAG_COND pub struct FlagCond; - - // LLIL_FLAG_GROUP pub struct FlagGroup; @@ -460,8 +452,6 @@ where } } - - // LLIL_TRAP pub struct Trap; @@ -476,23 +466,15 @@ where } } - - // 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; @@ -517,8 +499,10 @@ where }; 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); + error!( + "il expr @ {:x} contains constant 0x{:x} as {} byte value (doesn't fit!)", + self.op.address, self.op.operands[0], self.op.size + ); } } @@ -533,8 +517,6 @@ where } } - - // 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, @@ -569,8 +551,6 @@ where } } - - // LLIL_ADC, LLIL_SBB, LLIL_RLC, LLIL_RRC pub struct BinaryOpCarry; @@ -609,8 +589,6 @@ where } } - - // LLIL_DIVS_DP, LLIL_DIVU_DP, LLIL_MODU_DP, LLIL_MODS_DP pub struct DoublePrecDivOp; @@ -649,8 +627,6 @@ where } } - - // LLIL_PUSH, LLIL_NEG, LLIL_NOT, LLIL_SX, // LLIL_ZX, LLIL_LOW_PART, LLIL_BOOL_TO_INT, LLIL_UNIMPL_MEM pub struct UnaryOp; @@ -674,8 +650,6 @@ where } } - - // LLIL_CMP_X pub struct Condition; @@ -706,7 +680,6 @@ where } } - // LLIL_UNIMPL_MEM pub struct UnimplMem; diff --git a/rust/src/platform.rs b/rust/src/platform.rs index 3343bece..0e0b98b9 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -1,12 +1,26 @@ +// Copyright 2021 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::borrow::Borrow; use binaryninjacore_sys::*; use crate::architecture::{Architecture, CoreArchitecture}; use crate::callingconvention::CallingConvention; -use crate::types::QualifiedNameAndType; use crate::rc::*; use crate::string::*; +use crate::types::QualifiedNameAndType; #[derive(PartialEq, Eq, Hash)] pub struct Platform { @@ -35,13 +49,16 @@ macro_rules! cc_func { pub fn $set_name<A: Architecture>(&self, cc: &CallingConvention<A>) { let arch = self.arch(); - assert!(cc.arch_handle.borrow().as_ref().0 == arch.0, "use of calling convention with non-matching Platform architecture!"); + assert!( + cc.arch_handle.borrow().as_ref().0 == arch.0, + "use of calling convention with non-matching Platform architecture!" + ); unsafe { $set_api(self.handle, cc.handle); } } - } + }; } impl Platform { @@ -93,20 +110,26 @@ impl Platform { } } - pub fn list_by_os_and_arch<S: BnStrCompatible>(name: S, arch: &CoreArchitecture) -> Array<Platform> { + pub fn list_by_os_and_arch<S: BnStrCompatible>( + name: S, + arch: &CoreArchitecture, + ) -> Array<Platform> { let raw_name = name.as_bytes_with_nul(); unsafe { let mut count = 0; - let handles = BNGetPlatformListByOSAndArchitecture(raw_name.as_ref().as_ptr() as *mut _, - arch.0, &mut count); + let handles = BNGetPlatformListByOSAndArchitecture( + raw_name.as_ref().as_ptr() as *mut _, + arch.0, + &mut count, + ); Array::new(handles, count, ()) } } pub fn list_available_os() -> Array<BnString> { - unsafe { + unsafe { let mut count = 0; let list = BNGetPlatformOSList(&mut count); @@ -133,9 +156,7 @@ impl Platform { } pub fn arch(&self) -> CoreArchitecture { - unsafe { - CoreArchitecture::from_raw(BNGetPlatformArchitecture(self.handle)) - } + unsafe { CoreArchitecture::from_raw(BNGetPlatformArchitecture(self.handle)) } } pub fn register_os<S: BnStrCompatible>(&self, os: S) { @@ -146,20 +167,40 @@ impl Platform { } } - cc_func!(get_default_calling_convention, BNGetPlatformDefaultCallingConvention, - set_default_calling_convention, BNRegisterPlatformDefaultCallingConvention); + cc_func!( + get_default_calling_convention, + BNGetPlatformDefaultCallingConvention, + set_default_calling_convention, + BNRegisterPlatformDefaultCallingConvention + ); - cc_func!(get_cdecl_calling_convention, BNGetPlatformCdeclCallingConvention, - set_cdecl_calling_convention, BNRegisterPlatformCdeclCallingConvention); + cc_func!( + get_cdecl_calling_convention, + BNGetPlatformCdeclCallingConvention, + set_cdecl_calling_convention, + BNRegisterPlatformCdeclCallingConvention + ); - cc_func!(get_stdcall_calling_convention, BNGetPlatformStdcallCallingConvention, - set_stdcall_calling_convention, BNRegisterPlatformStdcallCallingConvention); + cc_func!( + get_stdcall_calling_convention, + BNGetPlatformStdcallCallingConvention, + set_stdcall_calling_convention, + BNRegisterPlatformStdcallCallingConvention + ); - cc_func!(get_fastcall_calling_convention, BNGetPlatformFastcallCallingConvention, - set_fastcall_calling_convention, BNRegisterPlatformFastcallCallingConvention); + cc_func!( + get_fastcall_calling_convention, + BNGetPlatformFastcallCallingConvention, + set_fastcall_calling_convention, + BNRegisterPlatformFastcallCallingConvention + ); - cc_func!(get_syscall_convention, BNGetPlatformSystemCallConvention, - set_syscall_convention, BNSetPlatformSystemCallConvention); + cc_func!( + get_syscall_convention, + BNGetPlatformSystemCallConvention, + set_syscall_convention, + BNSetPlatformSystemCallConvention + ); pub fn types(&self) -> Array<QualifiedNameAndType> { unsafe { diff --git a/rust/src/rc.rs b/rust/src/rc.rs index 3302fb3f..9264e3bd 100644 --- a/rust/src/rc.rs +++ b/rust/src/rc.rs @@ -1,9 +1,23 @@ -use std::marker::PhantomData; +// Copyright 2021 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::borrow::Borrow; -use std::ops::{Deref, DerefMut}; -use std::slice; +use std::marker::PhantomData; use std::mem; +use std::ops::{Deref, DerefMut}; use std::ptr; +use std::slice; // RefCountable provides an abstraction over the various // core-allocated refcounted resources. @@ -17,7 +31,7 @@ use std::ptr; // `T` does not have the `Drop` impl in order to allow more // efficient handling of core owned objects we receive pointers // to in callbacks -pub unsafe trait RefCountable: ToOwned<Owned=Ref<Self>> + Sized { +pub unsafe trait RefCountable: ToOwned<Owned = Ref<Self>> + Sized { unsafe fn inc_ref(handle: &Self) -> Ref<Self>; unsafe fn dec_ref(handle: &Self); } @@ -71,11 +85,13 @@ impl<T: RefCountable> Borrow<T> for Ref<T> { impl<T: RefCountable> Drop for Ref<T> { fn drop(&mut self) { - unsafe { RefCountable::dec_ref(&self.contents); } + unsafe { + RefCountable::dec_ref(&self.contents); + } } } -impl <T: RefCountable> Clone for Ref<T> { +impl<T: RefCountable> Clone for Ref<T> { fn clone(&self) -> Self { unsafe { RefCountable::inc_ref(&self.contents) } } @@ -99,7 +115,7 @@ impl<'a, T> Guard<'a, T> { pub(crate) unsafe fn new<O: 'a>(contents: T, _owner: &O) -> Self { Self { contents, - _guard: PhantomData + _guard: PhantomData, } } } @@ -149,15 +165,25 @@ where pub struct Array<P> where - P: CoreOwnedArrayProvider + P: CoreOwnedArrayProvider, { contents: *mut P::Raw, count: usize, context: P::Context, } -unsafe impl<P> Sync for Array<P> where P: CoreOwnedArrayProvider, P::Context: Sync {} -unsafe impl<P> Send for Array<P> where P: CoreOwnedArrayProvider, P::Context: Send {} +unsafe impl<P> Sync for Array<P> +where + P: CoreOwnedArrayProvider, + P::Context: Sync, +{ +} +unsafe impl<P> Send for Array<P> +where + P: CoreOwnedArrayProvider, + P::Context: Send, +{ +} impl<P: CoreOwnedArrayProvider> Array<P> { pub(crate) unsafe fn new(raw: *mut P::Raw, count: usize, context: P::Context) -> Self { @@ -186,12 +212,11 @@ impl<'a, P: 'a + CoreOwnedArrayWrapper<'a>> Array<P> { pub fn iter(&'a self) -> ArrayIter<'a, P> { ArrayIter { it: unsafe { slice::from_raw_parts(self.contents, self.count).iter() }, - context: &self.context + context: &self.context, } } } - impl<'a, P: 'a + CoreOwnedArrayWrapper<'a>> IntoIterator for &'a Array<P> { type Item = P::Wrapped; type IntoIter = ArrayIter<'a, P>; @@ -201,32 +226,40 @@ impl<'a, P: 'a + CoreOwnedArrayWrapper<'a>> IntoIterator for &'a Array<P> { } } - impl<P: CoreOwnedArrayProvider> Drop for Array<P> { fn drop(&mut self) { - unsafe { P::free(self.contents, self.count, &self.context); } + unsafe { + P::free(self.contents, self.count, &self.context); + } } } pub struct ArrayIter<'a, P> where - P: 'a + CoreOwnedArrayWrapper<'a> + P: 'a + CoreOwnedArrayWrapper<'a>, { it: slice::Iter<'a, P::Raw>, context: &'a P::Context, } -unsafe impl<'a, P> Send for ArrayIter<'a, P> where P: CoreOwnedArrayWrapper<'a>, P::Context: Sync {} +unsafe impl<'a, P> Send for ArrayIter<'a, P> +where + P: CoreOwnedArrayWrapper<'a>, + P::Context: Sync, +{ +} impl<'a, P> Iterator for ArrayIter<'a, P> where - P: 'a + CoreOwnedArrayWrapper<'a> + P: 'a + CoreOwnedArrayWrapper<'a>, { type Item = P::Wrapped; #[inline] fn next(&mut self) -> Option<P::Wrapped> { - self.it.next().map(|r| unsafe { P::wrap_raw(r, &self.context) }) + self.it + .next() + .map(|r| unsafe { P::wrap_raw(r, &self.context) }) } #[inline] @@ -237,7 +270,7 @@ where impl<'a, P> ExactSizeIterator for ArrayIter<'a, P> where - P: 'a + CoreOwnedArrayWrapper<'a> + P: 'a + CoreOwnedArrayWrapper<'a>, { #[inline] fn len(&self) -> usize { @@ -247,11 +280,13 @@ where impl<'a, P> DoubleEndedIterator for ArrayIter<'a, P> where - P: 'a + CoreOwnedArrayWrapper<'a> + P: 'a + CoreOwnedArrayWrapper<'a>, { #[inline] fn next_back(&mut self) -> Option<P::Wrapped> { - self.it.next_back().map(|r| unsafe { P::wrap_raw(r, &self.context) }) + self.it + .next_back() + .map(|r| unsafe { P::wrap_raw(r, &self.context) }) } } @@ -269,9 +304,7 @@ where P::Wrapped: Send, { pub fn par_iter(&'a self) -> ParArrayIter<'a, P> { - ParArrayIter { - it: self.iter(), - } + ParArrayIter { it: self.iter() } } } #[cfg(feature = "rayon")] @@ -294,7 +327,7 @@ where fn drive_unindexed<C>(self, consumer: C) -> C::Result where - C: UnindexedConsumer<Self::Item> + C: UnindexedConsumer<Self::Item>, { bridge(self, consumer) } @@ -313,7 +346,7 @@ where { fn drive<C>(self, consumer: C) -> C::Result where - C: Consumer<Self::Item> + C: Consumer<Self::Item>, { bridge(self, consumer) } @@ -324,7 +357,7 @@ where fn with_producer<CB>(self, callback: CB) -> CB::Output where - CB: ProducerCallback<Self::Item> + CB: ProducerCallback<Self::Item>, { callback.callback(ArrayIterProducer { it: self.it }) } @@ -355,7 +388,19 @@ where fn split_at(self, index: usize) -> (Self, Self) { let (l, r) = self.it.it.as_slice().split_at(index); - (Self { it: ArrayIter { it: l.iter(), context: self.it.context } }, - Self { it: ArrayIter { it: r.iter(), context: self.it.context } }) + ( + Self { + it: ArrayIter { + it: l.iter(), + context: self.it.context, + }, + }, + Self { + it: ArrayIter { + it: r.iter(), + context: self.it.context, + }, + }, + ) } } diff --git a/rust/src/section.rs b/rust/src/section.rs index d936e227..aae973f4 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -1,11 +1,25 @@ +// Copyright 2021 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; use std::ops::Range; use binaryninjacore_sys::*; use crate::binaryview::BinaryView; -use crate::string::*; use crate::rc::*; +use crate::string::*; pub enum Semantics { DefaultSection, @@ -64,7 +78,7 @@ impl Section { entry_size: 1, linked_section: None, info_section: None, - info_data: 0 + info_data: 0, } } @@ -89,7 +103,7 @@ impl Section { } pub fn address_range(&self) -> Range<u64> { - self.start() .. self.end() + self.start()..self.end() } pub fn semantics(&self) -> Semantics { @@ -123,7 +137,13 @@ impl Section { impl fmt::Debug for Section { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "<section '{}' @ {:x}-{:x}>", self.name(), self.start(), self.end()) + write!( + f, + "<section '{}' @ {:x}-{:x}>", + self.name(), + self.start(), + self.end() + ) } } @@ -233,18 +253,44 @@ impl<S: BnStrCompatible> SectionBuilder<S> { let nul_str = CStr::from_bytes_with_nul_unchecked(b"\x00").as_ptr(); let name_ptr = name.as_ref().as_ptr() as *mut _; - let ty_ptr = ty.as_ref().map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); - let linked_section_ptr = linked_section.as_ref().map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); - let info_section_ptr = info_section.as_ref().map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); + let ty_ptr = ty + .as_ref() + .map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); + let linked_section_ptr = linked_section + .as_ref() + .map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); + let info_section_ptr = info_section + .as_ref() + .map_or(nul_str, |s| s.as_ref().as_ptr() as *mut _); if self.is_auto { - BNAddAutoSection(view.handle, name_ptr, start, len, self.semantics.into(), - ty_ptr, self.align, self.entry_size, linked_section_ptr, - info_section_ptr, self.info_data); + BNAddAutoSection( + view.handle, + name_ptr, + start, + len, + self.semantics.into(), + ty_ptr, + self.align, + self.entry_size, + linked_section_ptr, + info_section_ptr, + self.info_data, + ); } else { - BNAddUserSection(view.handle, name_ptr, start, len, self.semantics.into(), - ty_ptr, self.align, self.entry_size, linked_section_ptr, - info_section_ptr, self.info_data); + BNAddUserSection( + view.handle, + name_ptr, + start, + len, + self.semantics.into(), + ty_ptr, + self.align, + self.entry_size, + linked_section_ptr, + info_section_ptr, + self.info_data, + ); } } } diff --git a/rust/src/segment.rs b/rust/src/segment.rs index 0985d0d3..b583e0e0 100644 --- a/rust/src/segment.rs +++ b/rust/src/segment.rs @@ -1,5 +1,18 @@ -use binaryninjacore_sys::*; +// Copyright 2021 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::*; use std::ops::Range; @@ -67,7 +80,9 @@ impl SegmentBuilder { pub(crate) fn create(self, view: &BinaryView) { let ea_start = self.ea.start; let ea_len = self.ea.end.wrapping_sub(ea_start); - let (b_start, b_len) = self.parent_backing.map_or((0, 0), |s| (s.start, s.end.wrapping_sub(s.start))); + let (b_start, b_len) = self + .parent_backing + .map_or((0, 0), |s| (s.start, s.end.wrapping_sub(s.start))); unsafe { if self.is_auto { @@ -101,7 +116,7 @@ impl Segment { pub fn address_range(&self) -> Range<u64> { let start = unsafe { BNSegmentGetStart(self.handle) }; let end = unsafe { BNSegmentGetEnd(self.handle) }; - start .. end + start..end } pub fn parent_backing(&self) -> Option<Range<u64>> { @@ -109,7 +124,7 @@ impl Segment { let end = unsafe { BNSegmentGetDataEnd(self.handle) }; if start != end { - Some(start .. end) + Some(start..end) } else { None } diff --git a/rust/src/settings.rs b/rust/src/settings.rs index 4f4ae58e..09fa14a6 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -1,3 +1,17 @@ +// Copyright 2021 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::*; pub use binaryninjacore_sys::BNSettingsScope as SettingsScope; @@ -45,5 +59,3 @@ unsafe impl RefCountable for Settings { BNFreeSettings(handle.handle); } } - - diff --git a/rust/src/string.rs b/rust/src/string.rs index 1b2e0913..5b20532e 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -1,16 +1,30 @@ -use std::fmt; +// Copyright 2021 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::borrow::Borrow; -use std::ops::Deref; use std::ffi::{CStr, CString}; -use std::os::raw; +use std::fmt; use std::mem; +use std::ops::Deref; +use std::os::raw; use crate::rc::*; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(C)] pub struct BnStr { - raw: [u8] + raw: [u8], } impl BnStr { @@ -19,7 +33,7 @@ impl BnStr { } pub fn as_str(&self) -> &str { - self.as_cstr().to_str().unwrap() + self.as_cstr().to_str().unwrap() } pub fn as_cstr(&self) -> &CStr { @@ -65,7 +79,7 @@ pub struct BnString { } /// A nul-terminated C string allocated by the core. -/// +/// /// Received from a variety of core function calls, and /// must be used when giving strings to the core from many /// core-invoked callbacks. @@ -78,7 +92,9 @@ impl BnString { unsafe { let ptr = raw.as_ref().as_ptr() as *mut _; - Self { raw: BNAllocString(ptr) } + Self { + raw: BNAllocString(ptr), + } } } diff --git a/rust/src/symbol.rs b/rust/src/symbol.rs index 44021426..2b3aa463 100644 --- a/rust/src/symbol.rs +++ b/rust/src/symbol.rs @@ -1,12 +1,27 @@ +// Copyright 2021 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; use std::ptr; -use binaryninjacore_sys::*; -use crate::string::*; use crate::rc::*; +use crate::string::*; +use binaryninjacore_sys::*; +// TODO : Rename #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum SymType { +pub enum SymbolType { Function, LibraryFunction, ImportAddress, @@ -16,34 +31,34 @@ pub enum SymType { External, } -impl From<BNSymbolType> for SymType { - fn from(bn: BNSymbolType) -> SymType { +impl From<BNSymbolType> for SymbolType { + fn from(bn: BNSymbolType) -> SymbolType { use self::BNSymbolType::*; match bn { - FunctionSymbol => SymType::Function, - LibraryFunctionSymbol => SymType::LibraryFunction, - ImportAddressSymbol => SymType::ImportAddress, - ImportedFunctionSymbol => SymType::ImportedFunction, - DataSymbol => SymType::Data, - ImportedDataSymbol => SymType::ImportedData, - ExternalSymbol => SymType::External, + FunctionSymbol => SymbolType::Function, + LibraryFunctionSymbol => SymbolType::LibraryFunction, + ImportAddressSymbol => SymbolType::ImportAddress, + ImportedFunctionSymbol => SymbolType::ImportedFunction, + DataSymbol => SymbolType::Data, + ImportedDataSymbol => SymbolType::ImportedData, + ExternalSymbol => SymbolType::External, } } } -impl Into<BNSymbolType> for SymType { +impl Into<BNSymbolType> for SymbolType { fn into(self) -> BNSymbolType { use self::BNSymbolType::*; match self { - SymType::Function => FunctionSymbol, - SymType::LibraryFunction => LibraryFunctionSymbol, - SymType::ImportAddress => ImportAddressSymbol, - SymType::ImportedFunction => ImportedFunctionSymbol, - SymType::Data => DataSymbol, - SymType::ImportedData => ImportedDataSymbol, - SymType::External => ExternalSymbol, + SymbolType::Function => FunctionSymbol, + SymbolType::LibraryFunction => LibraryFunctionSymbol, + SymbolType::ImportAddress => ImportAddressSymbol, + SymbolType::ImportedFunction => ImportedFunctionSymbol, + SymbolType::Data => DataSymbol, + SymbolType::ImportedData => ImportedDataSymbol, + SymbolType::External => ExternalSymbol, } } } @@ -82,9 +97,10 @@ impl Into<BNSymbolBinding> for Binding { } } +// TODO : Clean this up #[must_use] pub struct SymbolBuilder<S: BnStrCompatible> { - ty: SymType, + ty: SymbolType, binding: Binding, addr: u64, raw_name: S, @@ -121,13 +137,23 @@ impl<S: BnStrCompatible> SymbolBuilder<S> { unsafe { let raw_name = raw_name.as_ref().as_ptr() as *mut _; - let short_name = short_name.as_ref().map_or(raw_name, |s| s.as_ref().as_ptr() as *mut _); - let full_name = full_name.as_ref().map_or(raw_name, |s| s.as_ref().as_ptr() as *mut _); + let short_name = short_name + .as_ref() + .map_or(raw_name, |s| s.as_ref().as_ptr() as *mut _); + let full_name = full_name + .as_ref() + .map_or(raw_name, |s| s.as_ref().as_ptr() as *mut _); - let res = BNCreateSymbol(self.ty.into(), - short_name, full_name, raw_name, - self.addr, self.binding.into(), ptr::null_mut(), - self.ordinal); + let res = BNCreateSymbol( + self.ty.into(), + short_name, + full_name, + raw_name, + self.addr, + self.binding.into(), + ptr::null_mut(), + self.ordinal, + ); Ref::new(Symbol::from_raw(res)) } @@ -147,7 +173,7 @@ impl Symbol { Self { handle: raw } } - pub fn new<S: BnStrCompatible>(ty: SymType, raw_name: S, addr: u64) -> SymbolBuilder<S> { + pub fn new<S: BnStrCompatible>(ty: SymbolType, raw_name: S, addr: u64) -> SymbolBuilder<S> { SymbolBuilder { ty: ty, binding: Binding::None, @@ -159,7 +185,7 @@ impl Symbol { } } - pub fn sym_type(&self) -> SymType { + pub fn sym_type(&self) -> SymbolType { unsafe { BNGetSymbolType(self.handle).into() } } @@ -167,7 +193,7 @@ impl Symbol { unsafe { BNGetSymbolBinding(self.handle).into() } } - pub fn name(&self) -> BnString { + pub fn full_name(&self) -> BnString { unsafe { let name = BNGetSymbolFullName(self.handle); BnString::from_raw(name) @@ -199,7 +225,14 @@ impl Symbol { impl fmt::Debug for Symbol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "<sym {:?} '{}' @ {:x} (handle: {:?})>", self.sym_type(), self.name(), self.address(), self.handle) + write!( + f, + "<sym {:?} '{}' @ {:x} (handle: {:?})>", + self.sym_type(), + self.full_name(), + self.address(), + self.handle + ) } } diff --git a/rust/src/types.rs b/rust/src/types.rs index 80046f87..ec31c6e9 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1,37 +1,235 @@ -use std::mem; -use std::slice; +// Copyright 2021 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::*; +use std::{fmt, mem, ptr, slice}; + +use crate::architecture::Architecture; +use crate::string::{BnStr, BnStrCompatible, BnString}; use crate::rc::*; +pub type ReferenceType = BNReferenceType; +pub type TypeClass = BNTypeClass; +pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass; + +////////// +// Type + #[derive(PartialEq, Eq, Hash)] pub struct Type { pub(crate) handle: *mut BNType, + pub(crate) confidence: u8, } -unsafe impl Send for Type {} -unsafe impl Sync for Type {} - impl Type { pub(crate) unsafe fn from_raw(handle: *mut BNType) -> Self { debug_assert!(!handle.is_null()); - Self { handle } + Self { + handle, + // TODO : Remove this field and and make Confidence<Type> + confidence: 255, + } } -} -impl ToOwned for Type { - type Owned = Ref<Self>; + // TODO : Implement type builders (how I did with structures) + // pub(crate) unsafe fn from_builder(handle: *mut BNTypeBuilder) -> Self { + // debug_assert!(!handle.is_null()); - fn to_owned(&self) -> Self::Owned { - unsafe { RefCountable::inc_ref(self) } + // Self { handle } + // } + + // TODO : Add this to a real doc_string: + // use binaryninja::types::Type; + // let bv = unsafe { BinaryView::from_raw(view) }; + // let my_custom_type_1 = Type::named_int(5, false, "my_w"); + // let my_custom_type_2 = Type::int(5, false); + // bv.define_user_type("int_1", &my_custom_type_1); + // bv.define_user_type("int_2", &my_custom_type_2); + + pub fn void() -> Self { + unsafe { Type::from_raw(BNCreateVoidType()) } + } + + pub fn bool() -> Self { + unsafe { Type::from_raw(BNCreateBoolType()) } + } + + pub fn char() -> Self { + Type::int(1, true) + } + + pub fn int(width: usize, is_signed: bool) -> Self { + let mut is_signed = BoolWithConfidence::new(is_signed, 0); + unsafe { + Type::from_raw(BNCreateIntegerType( + width, + &mut is_signed.0, + BnString::new("").as_ptr() as *mut _, + )) + } + } + + pub fn named_int<S: BnStrCompatible>(width: usize, is_signed: bool, alt_name: S) -> Self { + let mut is_signed = BoolWithConfidence::new(is_signed, 0); + // let alt_name = BnString::new(alt_name); + let alt_name = alt_name.as_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data + + unsafe { + Type::from_raw(BNCreateIntegerType( + width, + &mut is_signed.0, + alt_name.as_ref().as_ptr() as _, + )) + } + } + + pub fn float(width: usize) -> Self { + unsafe { + Type::from_raw(BNCreateFloatType( + width, + BnString::new("").as_ptr() as *mut _, + )) + } + } + + pub fn named_float<S: BnStrCompatible>(width: usize, alt_name: S) -> Self { + // let alt_name = BnString::new(alt_name); + let alt_name = alt_name.as_bytes_with_nul(); // See same line in `named_int` above + + unsafe { Type::from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) } + } + + pub fn array(t: &Type, count: u64) -> Self { + let mut type_conf = TypeWithConfidence::new(&t, t.confidence); + unsafe { Type::from_raw(BNCreateArrayType(&mut type_conf.0, count)) } + } + + pub fn structure_type(structure_type: &mut Structure) -> Self { + unsafe { Type::from_raw(BNCreateStructureType(structure_type.handle())) } + } + + // TODO : Create enumeration type and finish implementing this + // pub fn enumeration<A: Architecture>( + // arch: A, + // enum_type: Enumeration, + // width: usize, + // is_signed: bool, + // ) -> Self { + // unsafe { Type::from_raw(BNCreateEnumerationType(arch, enum_type, width, is_signed)) } + // } + + pub fn named_type(type_reference: NamedTypeReference) -> Self { + unsafe { + Type::from_raw(BNFinalizeTypeBuilder(BNCreateNamedTypeReferenceBuilder( + type_reference.handle, + 0, + 1, + ))) + } + } + + pub fn named_type_from_type<S: BnStrCompatible>(name: S, t: &Type) -> Self { + let mut name = QualifiedName::from(name); + + unsafe { + Type::from_raw(BNFinalizeTypeBuilder( + BNCreateNamedTypeReferenceBuilderFromTypeAndId( + BnString::new("").as_ptr() as *mut _, + &mut name.0, // BNCreateNamedTypeReferenceBuilderFromTypeAndId copy's qualified the name + t.handle, + ), + )) + } + } + + // TODO : BNCreateFunctionType + + pub fn pointer<A: Architecture>(arch: &A, t: &Type) -> Self { + let mut is_const = BoolWithConfidence::new(false, 0); + let mut is_volatile = BoolWithConfidence::new(false, 0); + let mut type_conf = TypeWithConfidence::new(&t, t.confidence); + unsafe { + Type::from_raw(BNCreatePointerType( + arch.as_ref().0, + &mut type_conf.0, + &mut is_const.0, + &mut is_volatile.0, + ReferenceType::PointerReferenceType, + )) + } + } + + pub fn const_pointer<A: Architecture>(arch: &A, t: &Type) -> Self { + let mut is_const = BoolWithConfidence::new(true, 0); + let mut is_volatile = BoolWithConfidence::new(false, 0); + let mut type_conf = TypeWithConfidence::new(&t, t.confidence); + unsafe { + Type::from_raw(BNCreatePointerType( + arch.as_ref().0, + &mut type_conf.0, + &mut is_const.0, + &mut is_volatile.0, + ReferenceType::PointerReferenceType, + )) + } + } + + pub fn pointer_with_options<A: Architecture>( + arch: &A, + t: &Type, + is_const: bool, + is_volatile: bool, + ref_type: Option<ReferenceType>, + ) -> Self { + let mut is_const = BoolWithConfidence::new(is_const, 0); + let mut is_volatile = BoolWithConfidence::new(is_volatile, 0); + let mut type_conf = TypeWithConfidence::new(&t, t.confidence); + unsafe { + Type::from_raw(BNCreatePointerType( + arch.as_ref().0, + &mut type_conf.0, + &mut is_const.0, + &mut is_volatile.0, + ref_type.unwrap_or_else(|| ReferenceType::PointerReferenceType), + )) + } + } + + pub fn generate_auto_demangled_type_id<'a, S: BnStrCompatible>(name: S) -> &'a BnStr { + let mut name = QualifiedName::from(name); + unsafe { BnStr::from_raw(BNGenerateAutoDemangledTypeId(&mut name.0)) } + } +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", unsafe { + BnString::from_raw(BNGetTypeString(self.handle, ptr::null_mut())) + }) } } +unsafe impl Send for Type {} +unsafe impl Sync for Type {} + unsafe impl RefCountable for Type { unsafe fn inc_ref(handle: &Self) -> Ref<Self> { Ref::new(Self { handle: BNNewTypeReference(handle.handle), + confidence: handle.confidence, }) } @@ -40,17 +238,187 @@ unsafe impl RefCountable for Type { } } -#[repr(C)] -pub struct QualifiedName { - object: BNQualifiedName, +impl ToOwned for Type { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +/////////////// +// Structure + +#[derive(PartialEq, Eq, Hash)] +pub struct Structure { + pub builder: *mut BNStructureBuilder, + pub handle: Option<*mut BNStructure>, +} + +// TODO : Throw asserts or return results? +impl Structure { + // TODO : Turn this into a real docstring + // // Includes + // use binaryninja::types::{Structure, Type}; + + // // Define struct, set size (in bytes) + // let mut my_custom_struct = Structure::new(); + // my_custom_struct.set_width(17); + + // // Create some fields for the struct + // let field_1 = Type::named_int(5, false, "my_weird_int_type"); + // let field_2 = Type::int(4, false); + // let field_3 = Type::int(8, false); + + // // Assign those fields + // my_custom_struct.append(&field_1, "field_4"); + // my_custom_struct.insert(&field_1, "field_1", 0); + // my_custom_struct.insert(&field_2, "field_2", 5); + // my_custom_struct.insert(&field_3, "field_3", 9); + + // // Convert structure to type + // let my_custom_structure_type = Type::structure_type(&mut my_custom_struct); + + // // Add the struct to the binary view to use in analysis + // let bv = unsafe { BinaryView::from_raw(view) }; + // bv.define_user_type("my_custom_struct", &my_custom_structure_type); + + pub fn new() -> Self { + Structure { + builder: unsafe { BNCreateStructureBuilder() }, + handle: None, + } + } + + pub(crate) fn handle(&mut self) -> *mut BNStructure { + if let Some(handle) = self.handle { + handle + } else { + unsafe { + self.handle = Some(BNFinalizeStructureBuilder(self.builder)); + BNFreeStructureBuilder(self.builder); + } + self.handle.unwrap() + } + } + + pub fn set_width(&self, width: u64) { + assert!(self.handle.is_none()); + unsafe { + BNSetStructureBuilderWidth(self.builder, width); + } + } + + pub fn get_width(&self) -> u64 { + if let Some(structure_handle) = self.handle { + unsafe { BNGetStructureWidth(structure_handle) } + } else { + unsafe { BNGetStructureBuilderWidth(self.builder) } + } + } + + pub fn append<S: BnStrCompatible>(&self, t: &Type, name: S) { + assert!(self.handle.is_none()); + let mut type_conf = TypeWithConfidence::new(t, t.confidence); + let name = name.as_bytes_with_nul(); + unsafe { + BNAddStructureBuilderMember( + self.builder, + &mut type_conf.0, + name.as_ref().as_ptr() as _, + ); + } + } + + pub fn insert<S: BnStrCompatible>(&self, t: &Type, name: S, offset: u64) { + assert!(self.handle.is_none()); + let mut type_conf = TypeWithConfidence::new(t, t.confidence); + let name = name.as_bytes_with_nul(); + unsafe { + BNAddStructureBuilderMemberAtOffset( + self.builder, + &mut type_conf.0, + name.as_ref().as_ptr() as _, + offset, + ); + } + } + + // TODO : The other methods in the python version (alignment, packed, type, members, remove, replace, etc) } +// TODO : Use +// #[derive(PartialEq, Eq, Hash)] +// pub struct StructureMember { +// pub(crate) handle: *mut BNStructureMember, +// } + +// impl StructureMember { +// // pub fn new() -> Self {} +// } + +//////////////////////// +// BoolWithConfidence + +pub struct BoolWithConfidence(BNBoolWithConfidence); + +impl BoolWithConfidence { + pub fn new(value: bool, confidence: u8) -> Self { + BoolWithConfidence(BNBoolWithConfidence { value, confidence }) + } +} + +//////////////////////// +// TypeWithConfidence + +pub struct TypeWithConfidence(BNTypeWithConfidence); + +impl TypeWithConfidence { + pub fn new(t: &Type, confidence: u8) -> Self { + TypeWithConfidence(BNTypeWithConfidence { + type_: t.handle, + confidence, + }) + } +} + +//////////////////////// +// NamedTypeReference + +#[derive(PartialEq, Eq, Hash)] +pub struct NamedTypeReference { + pub(crate) handle: *mut BNNamedTypeReference, +} + +impl NamedTypeReference { + pub fn new<S: BnStrCompatible>( + type_class: NamedTypeReferenceClass, + type_id: S, + mut name: QualifiedName, + ) -> Self { + let type_id = type_id.as_bytes_with_nul(); + + NamedTypeReference { + handle: unsafe { + BNCreateNamedType(type_class, type_id.as_ref().as_ptr() as _, &mut name.0) + }, + } + } +} + +/////////////////// +// QualifiedName + +#[repr(transparent)] +pub struct QualifiedName(pub(crate) BNQualifiedName); + impl QualifiedName { + // TODO : I think this is bad pub fn string(&self) -> String { use std::ffi::CStr; unsafe { - slice::from_raw_parts(self.object.name, self.object.nameCount) + slice::from_raw_parts(self.0.name, self.0.nameCount) .iter() .map(|c| CStr::from_ptr(*c).to_string_lossy()) .collect::<Vec<_>>() @@ -59,34 +427,49 @@ impl QualifiedName { } } +impl<S: BnStrCompatible> From<S> for QualifiedName { + fn from(name: S) -> Self { + let join = BnString::new("::"); + let name = name.as_bytes_with_nul(); + let mut list = vec![name.as_ref().as_ptr() as *const _]; + + QualifiedName(BNQualifiedName { + name: unsafe { BNAllocStringList(list.as_mut_ptr(), 1) }, + join: join.into_raw(), + nameCount: 1, + }) + } +} + impl Drop for QualifiedName { fn drop(&mut self) { - unsafe { BNFreeQualifiedName(&mut self.object); } + unsafe { + BNFreeQualifiedName(&mut self.0); + } } } -#[repr(C)] -pub struct QualifiedNameAndType { - object: BNQualifiedNameAndType, -} +////////////////////////// +// QualifiedNameAndType + +#[repr(transparent)] +pub struct QualifiedNameAndType(pub(crate) BNQualifiedNameAndType); impl QualifiedNameAndType { pub fn name(&self) -> &QualifiedName { - unsafe { - mem::transmute(&self.object.name) - } + unsafe { mem::transmute(&self.0.name) } } pub fn type_object(&self) -> Guard<Type> { - unsafe { - Guard::new(Type::from_raw(self.object.type_), self) - } + unsafe { Guard::new(Type::from_raw(self.0.type_), self) } } } impl Drop for QualifiedNameAndType { fn drop(&mut self) { - unsafe { BNFreeQualifiedNameAndType(&mut self.object); } + unsafe { + BNFreeQualifiedNameAndType(&mut self.0); + } } } @@ -106,4 +489,3 @@ unsafe impl<'a> CoreOwnedArrayWrapper<'a> for QualifiedNameAndType { mem::transmute(raw) } } - |
