From 501fe3ec7a63a534fca3926a5fc4267f6886f089 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 7 Dec 2025 15:03:44 -0500 Subject: [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. --- rust/src/architecture/basic_block.rs | 261 +++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 rust/src/architecture/basic_block.rs (limited to 'rust/src/architecture/basic_block.rs') diff --git a/rust/src/architecture/basic_block.rs b/rust/src/architecture/basic_block.rs new file mode 100644 index 00000000..1867f50a --- /dev/null +++ b/rust/src/architecture/basic_block.rs @@ -0,0 +1,261 @@ +use crate::architecture::{CoreArchitecture, IndirectBranchInfo}; +use crate::basic_block::BasicBlock; +use crate::function::{Function, Location, NativeBlock}; +use crate::rc::Ref; +use binaryninjacore_sys::*; +use std::collections::{HashMap, HashSet}; + +pub struct BasicBlockAnalysisContext { + pub(crate) handle: *mut BNBasicBlockAnalysisContext, + contextual_returns_dirty: bool, + + // In + pub indirect_branches: Vec, + pub indirect_no_return_calls: HashSet, + 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, + + // Out + direct_code_references: HashMap, + direct_no_return_calls: HashSet, + halted_disassembly_addresses: HashSet, + inlined_unresolved_indirect_branches: HashSet, +} + +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::>(); + + 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::>(); + + 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::>(); + + 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::>(); + + 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::>(); + + 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::>(); + + 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::>(); + + 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, 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) { + self.direct_code_references + .entry(target) + .or_insert(src.into()); + } + + pub fn add_direct_no_return_call(&mut self, loc: impl Into) { + self.direct_no_return_calls.insert(loc.into()); + } + + pub fn add_halted_disassembly_address(&mut self, loc: impl Into) { + self.halted_disassembly_addresses.insert(loc.into()); + } + + pub fn add_inlined_unresolved_indirect_branch(&mut self, loc: impl Into) { + self.inlined_unresolved_indirect_branches.insert(loc.into()); + } + + pub fn create_basic_block( + &self, + arch: CoreArchitecture, + start: u64, + ) -> Option>> { + 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>) { + 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 = Vec::with_capacity(total); + let mut targets: Vec = 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 = 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 = 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 = 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 = Vec::with_capacity(total); + let mut values: Vec = 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) }; + } +} -- cgit v1.3.1