summaryrefslogtreecommitdiff
path: root/rust/src/architecture.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/architecture.rs')
-rw-r--r--rust/src/architecture.rs1484
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)
- }
-}