diff options
Diffstat (limited to 'rust/src/architecture.rs')
| -rw-r--r-- | rust/src/architecture.rs | 1484 |
1 files changed, 25 insertions, 1459 deletions
diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 2f0490f2..becf7639 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -23,44 +23,52 @@ use crate::{ calling_convention::CoreCallingConvention, data_buffer::DataBuffer, disassembly::InstructionTextToken, - function::{Function, NativeBlock}, + function::Function, platform::Platform, rc::*, relocation::CoreRelocationHandler, string::{IntoCStr, *}, types::{NameAndType, Type}, - BranchType, Endianness, + Endianness, }; use std::ops::Deref; use std::{ - borrow::{Borrow, Cow}, - collections::HashMap, - ffi::{c_char, c_int, c_void, CStr, CString}, - fmt::Display, + borrow::Borrow, + ffi::{c_char, c_void, CString}, hash::Hash, mem::MaybeUninit, }; -use crate::basic_block::BasicBlock; use crate::function_recognizer::FunctionRecognizer; use crate::relocation::{CustomRelocationHandlerHandle, RelocationHandler}; -use crate::variable::IndirectBranchInfo; use crate::confidence::Conf; -use crate::function::Location; use crate::low_level_il::expression::ValueExpr; use crate::low_level_il::lifting::{ get_default_flag_cond_llil, get_default_flag_write_llil, LowLevelILFlagWriteOp, }; use crate::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction}; -pub use binaryninjacore_sys::BNFlagRole as FlagRole; -pub use binaryninjacore_sys::BNImplicitRegisterExtend as ImplicitRegisterExtend; -pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition; -use std::collections::HashSet; -macro_rules! newtype { +pub mod basic_block; +pub mod branches; +pub mod flag; +pub mod instruction; +pub mod intrinsic; +pub mod register; + +// Re-export all the submodules to keep from breaking everyone's code. +// We split these out just to clarify each part, not necessarily to enforce an extra namespace. +pub use basic_block::*; +pub use branches::*; +pub use flag::*; +pub use instruction::*; +pub use intrinsic::*; +pub use register::*; + +#[macro_export] +macro_rules! new_id_type { ($name:ident, $inner_type:ty) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] + #[derive(std::fmt::Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct $name(pub $inner_type); impl From<$inner_type> for $name { @@ -75,377 +83,14 @@ macro_rules! newtype { } } - impl Display for $name { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } }; } -newtype!(RegisterId, u32); - -impl RegisterId { - pub fn is_temporary(&self) -> bool { - self.0 & 0x8000_0000 != 0 - } -} - -newtype!(RegisterStackId, u32); -newtype!(FlagId, u32); -// TODO: Make this NonZero<u32>? -newtype!(FlagWriteId, u32); -newtype!(FlagClassId, u32); -newtype!(FlagGroupId, u32); -newtype!(IntrinsicId, u32); - -#[derive(Default, Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum BranchKind { - #[default] - Unresolved, - Unconditional(u64), - False(u64), - True(u64), - Call(u64), - FunctionReturn, - SystemCall, - Indirect, - Exception, - UserDefined, -} - -#[derive(Default, Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct BranchInfo { - /// If `None` the target architecture is the same as the branch instruction. - pub arch: Option<CoreArchitecture>, - pub kind: BranchKind, -} - -impl BranchInfo { - /// Branches to an instruction with the current architecture. - pub fn new(kind: BranchKind) -> Self { - Self { arch: None, kind } - } - - /// Branches to an instruction with an explicit architecture. - /// - /// Use this if your architecture can transition to another architecture with a branch. - pub fn new_with_arch(kind: BranchKind, arch: CoreArchitecture) -> Self { - Self { - arch: Some(arch), - kind, - } - } - - pub fn target(&self) -> Option<u64> { - match self.kind { - BranchKind::Unconditional(target) => Some(target), - BranchKind::False(target) => Some(target), - BranchKind::True(target) => Some(target), - BranchKind::Call(target) => Some(target), - _ => None, - } - } -} - -impl From<BranchInfo> for BNBranchType { - fn from(value: BranchInfo) -> Self { - match value.kind { - BranchKind::Unresolved => BNBranchType::UnresolvedBranch, - BranchKind::Unconditional(_) => BNBranchType::UnconditionalBranch, - BranchKind::False(_) => BNBranchType::FalseBranch, - BranchKind::True(_) => BNBranchType::TrueBranch, - BranchKind::Call(_) => BNBranchType::CallDestination, - BranchKind::FunctionReturn => BNBranchType::FunctionReturn, - BranchKind::SystemCall => BNBranchType::SystemCall, - BranchKind::Indirect => BNBranchType::IndirectBranch, - BranchKind::Exception => BNBranchType::ExceptionBranch, - BranchKind::UserDefined => BNBranchType::UserDefinedBranch, - } - } -} - -impl From<BranchKind> for BranchInfo { - fn from(value: BranchKind) -> Self { - Self { - arch: None, - kind: value, - } - } -} - -impl From<BranchKind> for BranchType { - fn from(value: BranchKind) -> Self { - match value { - BranchKind::Unresolved => BranchType::UnresolvedBranch, - BranchKind::Unconditional(_) => BranchType::UnconditionalBranch, - BranchKind::True(_) => BranchType::TrueBranch, - BranchKind::False(_) => BranchType::FalseBranch, - BranchKind::Call(_) => BranchType::CallDestination, - BranchKind::FunctionReturn => BranchType::FunctionReturn, - BranchKind::SystemCall => BranchType::SystemCall, - BranchKind::Indirect => BranchType::IndirectBranch, - BranchKind::Exception => BranchType::ExceptionBranch, - BranchKind::UserDefined => BranchType::UserDefinedBranch, - } - } -} - -/// This is the number of branches that can be specified in an [`InstructionInfo`]. -pub const NUM_BRANCH_INFO: usize = 3; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct InstructionInfo { - pub length: usize, - // TODO: This field name is really long... - pub arch_transition_by_target_addr: bool, - pub delay_slots: u8, - pub branches: [Option<BranchInfo>; NUM_BRANCH_INFO], -} - -impl InstructionInfo { - // TODO: `new_with_delay_slot`? - pub fn new(length: usize, delay_slots: u8) -> Self { - Self { - length, - arch_transition_by_target_addr: false, - delay_slots, - branches: Default::default(), - } - } - - pub fn add_branch(&mut self, branch_info: impl Into<BranchInfo>) { - // Will go through each slot and attempt to add the branch info. - // TODO: Return a result with BranchInfoSlotsFilled error. - for branch in &mut self.branches { - if branch.is_none() { - *branch = Some(branch_info.into()); - return; - } - } - } -} - -impl From<BNInstructionInfo> for InstructionInfo { - fn from(value: BNInstructionInfo) -> Self { - // TODO: This is quite ugly, but we destructure the branch info so this will have to do. - let mut branch_info = [None; NUM_BRANCH_INFO]; - #[allow(clippy::needless_range_loop)] - for i in 0..value.branchCount.min(NUM_BRANCH_INFO) { - let branch_target = value.branchTarget[i]; - branch_info[i] = Some(BranchInfo { - kind: match value.branchType[i] { - BNBranchType::UnconditionalBranch => BranchKind::Unconditional(branch_target), - BNBranchType::FalseBranch => BranchKind::False(branch_target), - BNBranchType::TrueBranch => BranchKind::True(branch_target), - BNBranchType::CallDestination => BranchKind::Call(branch_target), - BNBranchType::FunctionReturn => BranchKind::FunctionReturn, - BNBranchType::SystemCall => BranchKind::SystemCall, - BNBranchType::IndirectBranch => BranchKind::Indirect, - BNBranchType::ExceptionBranch => BranchKind::Exception, - BNBranchType::UnresolvedBranch => BranchKind::Unresolved, - BNBranchType::UserDefinedBranch => BranchKind::UserDefined, - }, - arch: if value.branchArch[i].is_null() { - None - } else { - Some(unsafe { CoreArchitecture::from_raw(value.branchArch[i]) }) - }, - }); - } - Self { - length: value.length, - arch_transition_by_target_addr: value.archTransitionByTargetAddr, - delay_slots: value.delaySlots, - branches: branch_info, - } - } -} - -impl From<InstructionInfo> for BNInstructionInfo { - fn from(value: InstructionInfo) -> Self { - let branch_count = value.branches.into_iter().filter(Option::is_some).count(); - // TODO: This is quite ugly, but we destructure the branch info so this will have to do. - let branch_info_0 = value.branches[0].unwrap_or_default(); - let branch_info_1 = value.branches[1].unwrap_or_default(); - let branch_info_2 = value.branches[2].unwrap_or_default(); - Self { - length: value.length, - branchCount: branch_count, - archTransitionByTargetAddr: value.arch_transition_by_target_addr, - delaySlots: value.delay_slots, - branchType: [ - branch_info_0.into(), - branch_info_1.into(), - branch_info_2.into(), - ], - branchTarget: [ - branch_info_0.target().unwrap_or_default(), - branch_info_1.target().unwrap_or_default(), - branch_info_2.target().unwrap_or_default(), - ], - branchArch: [ - branch_info_0 - .arch - .map(|a| a.handle) - .unwrap_or(std::ptr::null_mut()), - branch_info_1 - .arch - .map(|a| a.handle) - .unwrap_or(std::ptr::null_mut()), - branch_info_2 - .arch - .map(|a| a.handle) - .unwrap_or(std::ptr::null_mut()), - ], - } - } -} - -pub trait RegisterInfo: Sized { - type RegType: Register<InfoType = Self>; - - fn parent(&self) -> Option<Self::RegType>; - fn size(&self) -> usize; - fn offset(&self) -> usize; - fn implicit_extend(&self) -> ImplicitRegisterExtend; -} - -pub trait Register: Debug + Sized + Clone + Copy + Hash + Eq { - type InfoType: RegisterInfo<RegType = Self>; - - fn name(&self) -> Cow<'_, str>; - fn info(&self) -> Self::InfoType; - - /// Unique identifier for this `Register`. - /// - /// *MUST* be in the range [0, 0x7fff_ffff] - fn id(&self) -> RegisterId; -} - -pub trait RegisterStackInfo: Sized { - type RegStackType: RegisterStack<InfoType = Self>; - type RegType: Register<InfoType = Self::RegInfoType>; - type RegInfoType: RegisterInfo<RegType = Self::RegType>; - - fn storage_regs(&self) -> (Self::RegType, usize); - fn top_relative_regs(&self) -> Option<(Self::RegType, usize)>; - fn stack_top_reg(&self) -> Self::RegType; -} - -pub trait RegisterStack: Debug + Sized + Clone + Copy { - type InfoType: RegisterStackInfo< - RegType = Self::RegType, - RegInfoType = Self::RegInfoType, - RegStackType = Self, - >; - type RegType: Register<InfoType = Self::RegInfoType>; - type RegInfoType: RegisterInfo<RegType = Self::RegType>; - - fn name(&self) -> Cow<'_, str>; - fn info(&self) -> Self::InfoType; - - /// Unique identifier for this `RegisterStack`. - /// - /// *MUST* be in the range [0, 0x7fff_ffff] - fn id(&self) -> RegisterStackId; -} - -pub trait Flag: Debug + Sized + Clone + Copy + Hash + Eq { - type FlagClass: FlagClass; - - fn name(&self) -> Cow<'_, str>; - fn role(&self, class: Option<Self::FlagClass>) -> FlagRole; - - /// Unique identifier for this `Flag`. - /// - /// *MUST* be in the range [0, 0x7fff_ffff] - fn id(&self) -> FlagId; -} - -pub trait FlagWrite: Sized + Clone + Copy { - type FlagType: Flag; - type FlagClass: FlagClass; - - fn name(&self) -> Cow<'_, str>; - fn class(&self) -> Option<Self::FlagClass>; - - /// Unique identifier for this `FlagWrite`. - /// - /// *MUST NOT* be 0. - /// *MUST* be in the range [1, 0x7fff_ffff] - fn id(&self) -> FlagWriteId; - - fn flags_written(&self) -> Vec<Self::FlagType>; -} - -pub trait FlagClass: Sized + Clone + Copy + Hash + Eq { - fn name(&self) -> Cow<'_, str>; - - /// Unique identifier for this `FlagClass`. - /// - /// *MUST NOT* be 0. - /// *MUST* be in the range [1, 0x7fff_ffff] - fn id(&self) -> FlagClassId; -} - -pub trait FlagGroup: Debug + Sized + Clone + Copy { - type FlagType: Flag; - type FlagClass: FlagClass; - - fn name(&self) -> Cow<'_, str>; - - /// Unique identifier for this `FlagGroup`. - /// - /// *MUST* be in the range [0, 0x7fff_ffff] - fn id(&self) -> FlagGroupId; - - /// Returns the list of flags that need to be resolved in order - /// to take the clean flag resolution path -- at time of writing, - /// all required flags must have been set by the same instruction, - /// and the 'querying' instruction must be reachable from *one* - /// instruction that sets all of these flags. - fn flags_required(&self) -> Vec<Self::FlagType>; - - /// Returns the mapping of Semantic Flag Classes to Flag Conditions, - /// in the context of this Flag Group. - /// - /// Example: - /// - /// If we have a group representing `cr1_lt` (as in PowerPC), we would - /// have multiple Semantic Flag Classes used by the different Flag Write - /// Types to represent the different comparisons, so for `cr1_lt` we - /// would return a mapping along the lines of: - /// - /// ```text - /// cr1_signed -> LLFC_SLT, - /// cr1_unsigned -> LLFC_ULT, - /// ``` - /// - /// This allows the core to recover the semantics of the comparison and - /// inline it into conditional branches when appropriate. - fn flag_conditions(&self) -> HashMap<Self::FlagClass, FlagCondition>; -} - -pub trait Intrinsic: Debug + Sized + Clone + Copy { - fn name(&self) -> Cow<'_, str>; - - /// Unique identifier for this `Intrinsic`. - fn id(&self) -> IntrinsicId; - - /// The intrinsic class for this `Intrinsic`. - fn class(&self) -> BNIntrinsicClass { - BNIntrinsicClass::GeneralIntrinsicClass - } - - // TODO: Maybe just return `(String, Conf<Ref<Type>>)`? - /// List of the input names and types for this intrinsic. - fn inputs(&self) -> Vec<NameAndType>; - - /// List of the output types for this intrinsic. - fn outputs(&self) -> Vec<Conf<Ref<Type>>>; -} - pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { type Handle: Borrow<Self> + Clone; @@ -673,742 +318,6 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> { fn handle(&self) -> Self::Handle; } -/// Type for architrectures that do not use register stacks. Will panic if accessed as a register stack. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct UnusedRegisterStackInfo<R: Register> { - _reg: std::marker::PhantomData<R>, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct UnusedRegisterStack<R: Register> { - _reg: std::marker::PhantomData<R>, -} - -impl<R: Register> RegisterStackInfo for UnusedRegisterStackInfo<R> { - type RegStackType = UnusedRegisterStack<R>; - type RegType = R; - type RegInfoType = R::InfoType; - - fn storage_regs(&self) -> (Self::RegType, usize) { - unreachable!() - } - fn top_relative_regs(&self) -> Option<(Self::RegType, usize)> { - unreachable!() - } - fn stack_top_reg(&self) -> Self::RegType { - unreachable!() - } -} - -impl<R: Register> RegisterStack for UnusedRegisterStack<R> { - type InfoType = UnusedRegisterStackInfo<R>; - type RegType = R; - type RegInfoType = R::InfoType; - - fn name(&self) -> Cow<'_, str> { - unreachable!() - } - fn id(&self) -> RegisterStackId { - unreachable!() - } - fn info(&self) -> Self::InfoType { - unreachable!() - } -} - -/// Type for architrectures that do not use flags. Will panic if accessed as a flag. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct UnusedFlag; - -impl Flag for UnusedFlag { - type FlagClass = Self; - fn name(&self) -> Cow<'_, str> { - unreachable!() - } - fn role(&self, _class: Option<Self::FlagClass>) -> FlagRole { - unreachable!() - } - fn id(&self) -> FlagId { - unreachable!() - } -} - -impl FlagWrite for UnusedFlag { - type FlagType = Self; - type FlagClass = Self; - fn name(&self) -> Cow<'_, str> { - unreachable!() - } - fn class(&self) -> Option<Self> { - unreachable!() - } - fn id(&self) -> FlagWriteId { - unreachable!() - } - fn flags_written(&self) -> Vec<Self::FlagType> { - unreachable!() - } -} - -impl FlagClass for UnusedFlag { - fn name(&self) -> Cow<'_, str> { - unreachable!() - } - fn id(&self) -> FlagClassId { - unreachable!() - } -} - -impl FlagGroup for UnusedFlag { - type FlagType = Self; - type FlagClass = Self; - fn name(&self) -> Cow<'_, str> { - unreachable!() - } - fn id(&self) -> FlagGroupId { - unreachable!() - } - fn flags_required(&self) -> Vec<Self::FlagType> { - unreachable!() - } - fn flag_conditions(&self) -> HashMap<Self, FlagCondition> { - unreachable!() - } -} - -/// Type for architrectures that do not use intrinsics. Will panic if accessed as an intrinsic. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct UnusedIntrinsic; - -impl Intrinsic for UnusedIntrinsic { - fn name(&self) -> Cow<'_, str> { - unreachable!() - } - fn id(&self) -> IntrinsicId { - unreachable!() - } - fn inputs(&self) -> Vec<NameAndType> { - unreachable!() - } - fn outputs(&self) -> Vec<Conf<Ref<Type>>> { - unreachable!() - } -} - -#[derive(Debug, Copy, Clone)] -pub struct CoreRegisterInfo { - arch: CoreArchitecture, - id: RegisterId, - info: BNRegisterInfo, -} - -impl CoreRegisterInfo { - pub fn new(arch: CoreArchitecture, id: RegisterId, info: BNRegisterInfo) -> Self { - Self { arch, id, info } - } -} - -impl RegisterInfo for CoreRegisterInfo { - type RegType = CoreRegister; - - fn parent(&self) -> Option<CoreRegister> { - if self.id != RegisterId::from(self.info.fullWidthRegister) { - Some(CoreRegister::new( - self.arch, - RegisterId::from(self.info.fullWidthRegister), - )?) - } else { - None - } - } - - fn size(&self) -> usize { - self.info.size - } - - fn offset(&self) -> usize { - self.info.offset - } - - fn implicit_extend(&self) -> ImplicitRegisterExtend { - self.info.extend - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct CoreRegister { - arch: CoreArchitecture, - id: RegisterId, -} - -impl CoreRegister { - pub fn new(arch: CoreArchitecture, id: RegisterId) -> Option<Self> { - let register = Self { arch, id }; - register.is_valid().then_some(register) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the register is actually valid. - let name = unsafe { BNGetArchitectureRegisterName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl Register for CoreRegister { - type InfoType = CoreRegisterInfo; - - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureRegisterName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn info(&self) -> CoreRegisterInfo { - CoreRegisterInfo::new(self.arch, self.id, unsafe { - BNGetArchitectureRegisterInfo(self.arch.handle, self.id.into()) - }) - } - - fn id(&self) -> RegisterId { - self.id - } -} - -impl Debug for CoreRegister { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CoreRegister") - .field("id", &self.id) - .field("name", &self.name()) - .finish() - } -} - -impl CoreArrayProvider for CoreRegister { - type Raw = u32; - type Context = CoreArchitecture; - type Wrapped<'a> = Self; -} - -unsafe impl CoreArrayProviderInner for CoreRegister { - unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { - BNFreeRegisterList(raw) - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::new(*context, RegisterId::from(*raw)).expect("Register list contains valid registers") - } -} - -#[derive(Debug, Copy, Clone)] -pub struct CoreRegisterStackInfo { - arch: CoreArchitecture, - // TODO: Wrap BNRegisterStackInfo - info: BNRegisterStackInfo, -} - -impl CoreRegisterStackInfo { - pub fn new(arch: CoreArchitecture, info: BNRegisterStackInfo) -> Self { - Self { arch, info } - } -} - -impl RegisterStackInfo for CoreRegisterStackInfo { - type RegStackType = CoreRegisterStack; - type RegType = CoreRegister; - type RegInfoType = CoreRegisterInfo; - - fn storage_regs(&self) -> (Self::RegType, usize) { - ( - CoreRegister::new(self.arch, RegisterId::from(self.info.firstStorageReg)) - .expect("Storage register is valid"), - self.info.storageCount as usize, - ) - } - - fn top_relative_regs(&self) -> Option<(Self::RegType, usize)> { - if self.info.topRelativeCount == 0 { - None - } else { - Some(( - CoreRegister::new(self.arch, RegisterId::from(self.info.firstTopRelativeReg)) - .expect("Top relative register is valid"), - self.info.topRelativeCount as usize, - )) - } - } - - fn stack_top_reg(&self) -> Self::RegType { - CoreRegister::new(self.arch, RegisterId::from(self.info.stackTopReg)) - .expect("Stack top register is valid") - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct CoreRegisterStack { - arch: CoreArchitecture, - id: RegisterStackId, -} - -impl CoreRegisterStack { - pub fn new(arch: CoreArchitecture, id: RegisterStackId) -> Option<Self> { - let register_stack = Self { arch, id }; - register_stack.is_valid().then_some(register_stack) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the stack register is actually valid. - let name = unsafe { BNGetArchitectureRegisterStackName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl RegisterStack for CoreRegisterStack { - type InfoType = CoreRegisterStackInfo; - type RegType = CoreRegister; - type RegInfoType = CoreRegisterInfo; - - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureRegisterStackName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn info(&self) -> CoreRegisterStackInfo { - CoreRegisterStackInfo::new(self.arch, unsafe { - BNGetArchitectureRegisterStackInfo(self.arch.handle, self.id.into()) - }) - } - - fn id(&self) -> RegisterStackId { - self.id - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct CoreFlag { - arch: CoreArchitecture, - id: FlagId, -} - -impl CoreFlag { - pub fn new(arch: CoreArchitecture, id: FlagId) -> Option<Self> { - let flag = Self { arch, id }; - flag.is_valid().then_some(flag) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the flag is actually valid. - let name = unsafe { BNGetArchitectureFlagName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl Flag for CoreFlag { - type FlagClass = CoreFlagClass; - - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureFlagName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn role(&self, class: Option<CoreFlagClass>) -> FlagRole { - unsafe { - BNGetArchitectureFlagRole( - self.arch.handle, - self.id.into(), - class.map(|c| c.id.0).unwrap_or(0), - ) - } - } - - fn id(&self) -> FlagId { - self.id - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct CoreFlagWrite { - arch: CoreArchitecture, - id: FlagWriteId, -} - -impl CoreFlagWrite { - pub fn new(arch: CoreArchitecture, id: FlagWriteId) -> Option<Self> { - let flag_write = Self { arch, id }; - flag_write.is_valid().then_some(flag_write) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the flag write is actually valid. - let name = unsafe { BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl FlagWrite for CoreFlagWrite { - type FlagType = CoreFlag; - type FlagClass = CoreFlagClass; - - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn class(&self) -> Option<CoreFlagClass> { - let class = unsafe { - BNGetArchitectureSemanticClassForFlagWriteType(self.arch.handle, self.id.into()) - }; - - match class { - 0 => None, - class_id => Some(CoreFlagClass::new(self.arch, class_id.into())?), - } - } - - fn id(&self) -> FlagWriteId { - self.id - } - - fn flags_written(&self) -> Vec<CoreFlag> { - let mut count: usize = 0; - let regs: *mut u32 = unsafe { - BNGetArchitectureFlagsWrittenByFlagWriteType( - self.arch.handle, - self.id.into(), - &mut count, - ) - }; - - let ret = unsafe { - std::slice::from_raw_parts(regs, count) - .iter() - .map(|id| FlagId::from(*id)) - .filter_map(|reg| CoreFlag::new(self.arch, reg)) - .collect() - }; - - unsafe { - BNFreeRegisterList(regs); - } - - ret - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct CoreFlagClass { - arch: CoreArchitecture, - id: FlagClassId, -} - -impl CoreFlagClass { - pub fn new(arch: CoreArchitecture, id: FlagClassId) -> Option<Self> { - let flag = Self { arch, id }; - flag.is_valid().then_some(flag) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the flag is actually valid. - let name = - unsafe { BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl FlagClass for CoreFlagClass { - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn id(&self) -> FlagClassId { - self.id - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct CoreFlagGroup { - arch: CoreArchitecture, - id: FlagGroupId, -} - -impl CoreFlagGroup { - pub fn new(arch: CoreArchitecture, id: FlagGroupId) -> Option<Self> { - let flag_group = Self { arch, id }; - flag_group.is_valid().then_some(flag_group) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the flag group is actually valid. - let name = - unsafe { BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl FlagGroup for CoreFlagGroup { - type FlagType = CoreFlag; - type FlagClass = CoreFlagClass; - - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn id(&self) -> FlagGroupId { - self.id - } - - fn flags_required(&self) -> Vec<CoreFlag> { - let mut count: usize = 0; - let regs: *mut u32 = unsafe { - BNGetArchitectureFlagsRequiredForSemanticFlagGroup( - self.arch.handle, - self.id.into(), - &mut count, - ) - }; - - let ret = unsafe { - std::slice::from_raw_parts(regs, count) - .iter() - .map(|id| FlagId::from(*id)) - .filter_map(|reg| CoreFlag::new(self.arch, reg)) - .collect() - }; - - unsafe { - BNFreeRegisterList(regs); - } - - ret - } - - fn flag_conditions(&self) -> HashMap<CoreFlagClass, FlagCondition> { - let mut count: usize = 0; - - unsafe { - let flag_conds = BNGetArchitectureFlagConditionsForSemanticFlagGroup( - self.arch.handle, - self.id.into(), - &mut count, - ); - - let ret = std::slice::from_raw_parts_mut(flag_conds, count) - .iter() - .filter_map(|class_cond| { - Some(( - CoreFlagClass::new(self.arch, class_cond.semanticClass.into())?, - class_cond.condition, - )) - }) - .collect(); - - BNFreeFlagConditionsForSemanticFlagGroup(flag_conds); - - ret - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct CoreIntrinsic { - pub arch: CoreArchitecture, - pub id: IntrinsicId, -} - -impl CoreIntrinsic { - pub fn new(arch: CoreArchitecture, id: IntrinsicId) -> Option<Self> { - let intrinsic = Self { arch, id }; - intrinsic.is_valid().then_some(intrinsic) - } - - fn is_valid(&self) -> bool { - // We check the name to see if the intrinsic is actually valid. - let name = unsafe { BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into()) }; - match name.is_null() { - true => false, - false => { - unsafe { BNFreeString(name) }; - true - } - } - } -} - -impl Intrinsic for CoreIntrinsic { - fn name(&self) -> Cow<'_, str> { - unsafe { - let name = BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into()); - - // We need to guarantee ownership, as if we're still - // a Borrowed variant we're about to free the underlying - // memory. - // TODO: ^ the above assertion nullifies any benefit to passing back Cow tho? - let res = CStr::from_ptr(name); - let res = res.to_string_lossy().into_owned().into(); - - BNFreeString(name); - - res - } - } - - fn id(&self) -> IntrinsicId { - self.id - } - - fn class(&self) -> BNIntrinsicClass { - unsafe { BNGetArchitectureIntrinsicClass(self.arch.handle, self.id.into()) } - } - - fn inputs(&self) -> Vec<NameAndType> { - let mut count: usize = 0; - unsafe { - let inputs = - BNGetArchitectureIntrinsicInputs(self.arch.handle, self.id.into(), &mut count); - - let ret = std::slice::from_raw_parts_mut(inputs, count) - .iter() - .map(NameAndType::from_raw) - .collect(); - - BNFreeNameAndTypeList(inputs, count); - - ret - } - } - - fn outputs(&self) -> Vec<Conf<Ref<Type>>> { - let mut count: usize = 0; - unsafe { - let inputs = - BNGetArchitectureIntrinsicOutputs(self.arch.handle, self.id.into(), &mut count); - - let ret = std::slice::from_raw_parts_mut(inputs, count) - .iter() - .map(Conf::<Ref<Type>>::from_raw) - .collect(); - - BNFreeOutputTypeList(inputs, count); - - ret - } - } -} - -impl Debug for CoreIntrinsic { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CoreIntrinsic") - .field("id", &self.id) - .field("name", &self.name()) - .field("class", &self.class()) - .field("inputs", &self.inputs()) - .field("outputs", &self.outputs()) - .finish() - } -} - // TODO: WTF?!?!?!? pub struct CoreArchitectureList(*mut *mut BNArchitecture, usize); @@ -1954,261 +863,6 @@ impl Architecture for CoreArchitecture { } } -pub struct BasicBlockAnalysisContext { - pub(crate) handle: *mut BNBasicBlockAnalysisContext, - contextual_returns_dirty: bool, - - // In - pub indirect_branches: Vec<IndirectBranchInfo>, - pub indirect_no_return_calls: HashSet<Location>, - pub analysis_skip_override: BNFunctionAnalysisSkipOverride, - pub guided_analysis_mode: bool, - pub trigger_guided_on_invalid_instruction: bool, - pub translate_tail_calls: bool, - pub disallow_branch_to_string: bool, - pub max_function_size: u64, - - // In/Out - pub max_size_reached: bool, - contextual_returns: HashMap<Location, bool>, - - // Out - direct_code_references: HashMap<u64, Location>, - direct_no_return_calls: HashSet<Location>, - halted_disassembly_addresses: HashSet<Location>, - inlined_unresolved_indirect_branches: HashSet<Location>, -} - -impl BasicBlockAnalysisContext { - pub unsafe fn from_raw(handle: *mut BNBasicBlockAnalysisContext) -> Self { - debug_assert!(!handle.is_null()); - - let ctx_ref = &*handle; - - let indirect_branches = (0..ctx_ref.indirectBranchesCount) - .map(|i| { - let raw: BNIndirectBranchInfo = - unsafe { std::ptr::read(ctx_ref.indirectBranches.add(i)) }; - IndirectBranchInfo::from(raw) - }) - .collect::<Vec<_>>(); - - let indirect_no_return_calls = (0..ctx_ref.indirectNoReturnCallsCount) - .map(|i| { - let raw = unsafe { std::ptr::read(ctx_ref.indirectNoReturnCalls.add(i)) }; - Location::from(raw) - }) - .collect::<HashSet<_>>(); - - let contextual_returns = (0..ctx_ref.contextualFunctionReturnCount) - .map(|i| { - let loc = unsafe { - let raw = std::ptr::read(ctx_ref.contextualFunctionReturnLocations.add(i)); - Location::from(raw) - }; - let val = unsafe { *ctx_ref.contextualFunctionReturnValues.add(i) }; - (loc, val) - }) - .collect::<HashMap<_, _>>(); - - let direct_code_references = (0..ctx_ref.directRefCount) - .map(|i| { - let src = unsafe { - let raw = std::ptr::read(ctx_ref.directRefSources.add(i)); - Location::from(raw) - }; - let tgt = unsafe { *ctx_ref.directRefTargets.add(i) }; - (tgt, src) - }) - .collect::<HashMap<_, _>>(); - - let direct_no_return_calls = (0..ctx_ref.directNoReturnCallsCount) - .map(|i| { - let raw = unsafe { std::ptr::read(ctx_ref.directNoReturnCalls.add(i)) }; - Location::from(raw) - }) - .collect::<HashSet<_>>(); - - let halted_disassembly_addresses = (0..ctx_ref.haltedDisassemblyAddressesCount) - .map(|i| { - let raw = unsafe { std::ptr::read(ctx_ref.haltedDisassemblyAddresses.add(i)) }; - Location::from(raw) - }) - .collect::<HashSet<_>>(); - - let inlined_unresolved_indirect_branches = (0..ctx_ref - .inlinedUnresolvedIndirectBranchCount) - .map(|i| { - let raw = - unsafe { std::ptr::read(ctx_ref.inlinedUnresolvedIndirectBranches.add(i)) }; - Location::from(raw) - }) - .collect::<HashSet<_>>(); - - BasicBlockAnalysisContext { - handle, - contextual_returns_dirty: false, - indirect_branches, - indirect_no_return_calls, - analysis_skip_override: ctx_ref.analysisSkipOverride, - guided_analysis_mode: ctx_ref.guidedAnalysisMode, - trigger_guided_on_invalid_instruction: ctx_ref.triggerGuidedOnInvalidInstruction, - translate_tail_calls: ctx_ref.translateTailCalls, - disallow_branch_to_string: ctx_ref.disallowBranchToString, - max_function_size: ctx_ref.maxFunctionSize, - max_size_reached: ctx_ref.maxSizeReached, - contextual_returns, - direct_code_references, - direct_no_return_calls, - halted_disassembly_addresses, - inlined_unresolved_indirect_branches, - } - } - - pub fn add_contextual_return(&mut self, loc: impl Into<Location>, value: bool) { - let loc = loc.into(); - if !self.contextual_returns.contains_key(&loc) { - self.contextual_returns_dirty = true; - } - - self.contextual_returns.insert(loc, value); - } - - pub fn add_direct_code_reference(&mut self, target: u64, src: impl Into<Location>) { - self.direct_code_references - .entry(target) - .or_insert(src.into()); - } - - pub fn add_direct_no_return_call(&mut self, loc: impl Into<Location>) { - self.direct_no_return_calls.insert(loc.into()); - } - - pub fn add_halted_disassembly_address(&mut self, loc: impl Into<Location>) { - self.halted_disassembly_addresses.insert(loc.into()); - } - - pub fn add_inlined_unresolved_indirect_branch(&mut self, loc: impl Into<Location>) { - self.inlined_unresolved_indirect_branches.insert(loc.into()); - } - - pub fn create_basic_block( - &self, - arch: CoreArchitecture, - start: u64, - ) -> Option<Ref<BasicBlock<NativeBlock>>> { - let raw_block = - unsafe { BNAnalyzeBasicBlocksContextCreateBasicBlock(self.handle, arch.handle, start) }; - - if raw_block.is_null() { - return None; - } - - unsafe { Some(BasicBlock::ref_from_raw(raw_block, NativeBlock::new())) } - } - - pub fn add_basic_block(&self, block: Ref<BasicBlock<NativeBlock>>) { - unsafe { - BNAnalyzeBasicBlocksContextAddBasicBlockToFunction(self.handle, block.handle); - } - } - - pub fn add_temp_outgoing_reference(&self, target: &Function) { - unsafe { - BNAnalyzeBasicBlocksContextAddTempReference(self.handle, target.handle); - } - } - - pub fn finalize(&mut self) { - if !self.direct_code_references.is_empty() { - let total = self.direct_code_references.len(); - let mut sources: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total); - let mut targets: Vec<u64> = Vec::with_capacity(total); - for (target, src) in &self.direct_code_references { - sources.push(BNArchitectureAndAddress::from(src)); - targets.push(*target); - } - unsafe { - BNAnalyzeBasicBlocksContextSetDirectCodeReferences( - self.handle, - sources.as_mut_ptr(), - targets.as_mut_ptr(), - total, - ); - } - } - - if !self.direct_no_return_calls.is_empty() { - let total = self.direct_no_return_calls.len(); - let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total); - for loc in &self.direct_no_return_calls { - locations.push(BNArchitectureAndAddress::from(loc)); - } - unsafe { - BNAnalyzeBasicBlocksContextSetDirectNoReturnCalls( - self.handle, - locations.as_mut_ptr(), - total, - ); - } - } - - if !self.halted_disassembly_addresses.is_empty() { - let total = self.halted_disassembly_addresses.len(); - let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total); - for loc in &self.halted_disassembly_addresses { - locations.push(BNArchitectureAndAddress::from(loc)); - } - unsafe { - BNAnalyzeBasicBlocksContextSetHaltedDisassemblyAddresses( - self.handle, - locations.as_mut_ptr(), - total, - ); - } - } - - if !self.inlined_unresolved_indirect_branches.is_empty() { - let total = self.inlined_unresolved_indirect_branches.len(); - let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total); - for loc in &self.inlined_unresolved_indirect_branches { - locations.push(BNArchitectureAndAddress::from(loc)); - } - unsafe { - BNAnalyzeBasicBlocksContextSetInlinedUnresolvedIndirectBranches( - self.handle, - locations.as_mut_ptr(), - total, - ); - } - } - - unsafe { - (*self.handle).maxSizeReached = self.max_size_reached; - } - - if self.contextual_returns_dirty { - let total = self.contextual_returns.len(); - let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total); - let mut values: Vec<bool> = Vec::with_capacity(total); - for (loc, value) in &self.contextual_returns { - locations.push(BNArchitectureAndAddress::from(loc)); - values.push(*value); - } - unsafe { - BNAnalyzeBasicBlocksContextSetContextualFunctionReturns( - self.handle, - locations.as_mut_ptr(), - values.as_mut_ptr(), - total, - ); - } - } - - unsafe { BNAnalyzeBasicBlocksContextFinalize(self.handle) }; - } -} - impl Debug for CoreArchitecture { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("CoreArchitecture") @@ -3590,91 +2244,3 @@ where unsafe { &*self.handle } } } - -#[repr(i32)] -pub enum LlvmServicesDialect { - Unspecified = 0, - Att = 1, - Intel = 2, -} - -#[repr(i32)] -pub enum LlvmServicesCodeModel { - Default = 0, - Small = 1, - Kernel = 2, - Medium = 3, - Large = 4, -} - -#[repr(i32)] -pub enum LlvmServicesRelocMode { - Static = 0, - PIC = 1, - DynamicNoPIC = 2, -} - -pub fn llvm_assemble( - code: &str, - dialect: LlvmServicesDialect, - arch_triple: &str, - code_model: LlvmServicesCodeModel, - reloc_mode: LlvmServicesRelocMode, -) -> Result<Vec<u8>, String> { - let code = CString::new(code).map_err(|_| "Invalid encoding in code string".to_string())?; - let arch_triple = CString::new(arch_triple) - .map_err(|_| "Invalid encoding in architecture triple string".to_string())?; - let mut out_bytes: *mut c_char = std::ptr::null_mut(); - let mut out_bytes_len: c_int = 0; - let mut err_bytes: *mut c_char = std::ptr::null_mut(); - let mut err_len: c_int = 0; - - unsafe { - BNLlvmServicesInit(); - } - - let result = unsafe { - BNLlvmServicesAssemble( - code.as_ptr(), - dialect as i32, - arch_triple.as_ptr(), - code_model as i32, - reloc_mode as i32, - &mut out_bytes as *mut *mut c_char, - &mut out_bytes_len as *mut c_int, - &mut err_bytes as *mut *mut c_char, - &mut err_len as *mut c_int, - ) - }; - - let out = if out_bytes_len == 0 { - Vec::new() - } else { - unsafe { - std::slice::from_raw_parts( - out_bytes as *const c_char as *const u8, - out_bytes_len as usize, - ) - } - .to_vec() - }; - - let errors = if err_len == 0 { - "".into() - } else { - String::from_utf8_lossy(unsafe { - std::slice::from_raw_parts(err_bytes as *const c_char as *const u8, err_len as usize) - }) - .into_owned() - }; - - unsafe { - BNLlvmServicesAssembleFree(out_bytes, err_bytes); - } - - if result == 0 { - Ok(out) - } else { - Err(errors) - } -} |
