diff options
| author | Mason Reed <mason@vector35.com> | 2025-12-07 15:03:44 -0500 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2025-12-10 17:35:19 -0500 |
| commit | 501fe3ec7a63a534fca3926a5fc4267f6886f089 (patch) | |
| tree | 0e3e64fcef0a3180950f3e8fb3758ebcbf5d02e7 /rust/src/architecture/instruction.rs | |
| parent | 7090d904513c3e80321bb6a8aba9c3b37d809bac (diff) | |
[Rust] Move architecture module code into more reasonable files
To keep backwards compatibility for commonly referenced code we re-export them within the architecture module.
Also does some light refactoring of some newly added APIs to keep them more consistent with other parts of the codebase.
Diffstat (limited to 'rust/src/architecture/instruction.rs')
| -rw-r--r-- | rust/src/architecture/instruction.rs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/rust/src/architecture/instruction.rs b/rust/src/architecture/instruction.rs new file mode 100644 index 00000000..94cb788b --- /dev/null +++ b/rust/src/architecture/instruction.rs @@ -0,0 +1,114 @@ +use crate::architecture::{BranchInfo, BranchKind, CoreArchitecture}; +use binaryninjacore_sys::*; + +/// 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(), + } + } + + /// Add a branch to this [`InstructionInfo`], maximum of 3 branches may be added (as per [`NUM_BRANCH_INFO`]). + 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()), + ], + } + } +} |
