From d3140edec185f47235b9e4642bdd56d6c585a341 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Thu, 21 Jan 2021 18:27:48 +0000 Subject: This is a combination of 23 commits, the work of Ryan Snyder: Initial fresh repo Add support for recent calling convention API updates and folds the binaryninjacore-sys crate directly into this one. Add support for auto function analysis suppression Finish moving binaryninjacore-sys back into this crate Update for Symbol/Segment core API changes Update for Symbol API cleanup api: advance submodule reference, support Token changes arch/lifting: support for flags in custom architectures arch/lifting: support default flag write behaviors, handle more ops build: enable headless binary support on MacOS via evil hack bv: add BinaryView wrapper support, remove wrong comment api: update to latest binja dev branch support deps: bump dep versions rust: bump to 2018 edition api: bump to avoid cargo submodule brokenness build: improve binaryninja path detection; enable linux linkhack bv: stub for bv load settings arch: fix flag related crash, minor llil update api: update for recent changes macos: disable linkhack briefly --- rust/src/basicblock.rs | 274 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 rust/src/basicblock.rs (limited to 'rust/src/basicblock.rs') diff --git a/rust/src/basicblock.rs b/rust/src/basicblock.rs new file mode 100644 index 00000000..db7989a0 --- /dev/null +++ b/rust/src/basicblock.rs @@ -0,0 +1,274 @@ +use std::fmt; + +use binaryninjacore_sys::*; +use crate::architecture::CoreArchitecture; +use crate::function::Function; + +use crate::rc::*; + +enum EdgeDirection { + Incoming, + Outgoing, +} + +pub struct Edge<'a, C: 'a + BlockContext> { + branch: super::BranchType, + back_edge: bool, + source: Guard<'a, BasicBlock>, + target: Guard<'a, BasicBlock>, +} + +impl<'a, C: 'a + BlockContext> Edge<'a, C> { + pub fn branch_type(&self) -> super::BranchType { + self.branch + } + + pub fn back_edge(&self) -> bool { + self.back_edge + } + + pub fn source(&self) -> &BasicBlock { + &*self.source + } + + pub fn target(&self) -> &BasicBlock { + &*self.target + } +} + +impl<'a, C: 'a + fmt::Debug + BlockContext> fmt::Debug for Edge<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?} ({}) {:?} -> {:?}", self.branch, self.back_edge, &*self.source, &*self.target) + } +} + +pub struct EdgeContext<'a, C: 'a + BlockContext> { + dir: EdgeDirection, + orig_block: &'a BasicBlock, +} + +unsafe impl<'a, C: 'a + BlockContext> CoreOwnedArrayProvider for Edge<'a, C> { + type Raw = BNBasicBlockEdge; + type Context = EdgeContext<'a, C>; + + unsafe fn free(raw: *mut BNBasicBlockEdge, count: usize, _context: &Self::Context) { + BNFreeBasicBlockEdgeList(raw, count); + } +} + +unsafe impl<'a, C: 'a + BlockContext> CoreOwnedArrayWrapper<'a> for Edge<'a, C> { + type Wrapped = Edge<'a, C>; + + unsafe fn wrap_raw(raw: &'a BNBasicBlockEdge, context: &'a Self::Context) -> Edge<'a, C> { + let edge_target = Guard::new(BasicBlock::from_raw(raw.target, context.orig_block.context.clone()), raw); + let orig_block = Guard::new(BasicBlock::from_raw(context.orig_block.handle, context.orig_block.context.clone()), raw); + + let (source, target) = match context.dir { + EdgeDirection::Incoming => (edge_target, orig_block), + EdgeDirection::Outgoing => (orig_block, edge_target), + }; + + Edge { + branch: raw.type_, + back_edge: raw.backEdge, + source: source, + target: target, + } + } +} + +pub trait BlockContext: Clone + Sync + Send + Sized { + type Instruction; + type Iter: Iterator; + + fn start(&self, block: &BasicBlock) -> Self::Instruction; + fn iter(&self, block: &BasicBlock) -> Self::Iter; +} + +#[derive(PartialEq, Eq, Hash)] +pub struct BasicBlock { + pub(crate) handle: *mut BNBasicBlock, + context: C, +} + +unsafe impl Send for BasicBlock {} +unsafe impl Sync for BasicBlock {} + +impl BasicBlock { + pub(crate) unsafe fn from_raw(handle: *mut BNBasicBlock, context: C) -> Self { + Self { handle, context } + } + + // TODO native bb vs il bbs + pub fn function(&self) -> Ref { + unsafe { + let func = BNGetBasicBlockFunction(self.handle); + Ref::new(Function::from_raw(func)) + } + } + + pub fn arch(&self) -> CoreArchitecture { + unsafe { + let arch = BNGetBasicBlockArchitecture(self.handle); + CoreArchitecture::from_raw(arch) + } + } + + pub fn iter(&self) -> C::Iter { + self.context.iter(self) + } + + pub fn raw_start(&self) -> u64 { + unsafe { BNGetBasicBlockStart(self.handle) } + } + + pub fn raw_end(&self) -> u64 { + unsafe { BNGetBasicBlockEnd(self.handle) } + } + + pub fn raw_length(&self) -> u64 { + unsafe { BNGetBasicBlockLength(self.handle) } + } + + pub fn incoming_edges(&self) -> Array> { + unsafe { + let mut count = 0; + let edges = BNGetBasicBlockIncomingEdges(self.handle, &mut count); + + Array::new(edges, count, EdgeContext { + dir: EdgeDirection::Incoming, + orig_block: self, + }) + } + } + + pub fn outgoing_edges(&self) -> Array> { + unsafe { + let mut count = 0; + let edges = BNGetBasicBlockOutgoingEdges(self.handle, &mut count); + + Array::new(edges, count, EdgeContext { + dir: EdgeDirection::Outgoing, + orig_block: self, + }) + } + } + + // is this valid for il blocks? + pub fn has_undetermined_outgoing_edges(&self) -> bool { + unsafe { BNBasicBlockHasUndeterminedOutgoingEdges(self.handle) } + } + + pub fn can_exit(&self) -> bool { + unsafe { BNBasicBlockCanExit(self.handle) } + } + + pub fn index(&self) -> usize { + unsafe { BNGetBasicBlockIndex(self.handle) } + } + + pub fn immediate_dominator(&self) -> Option> { + unsafe { + let block = BNGetBasicBlockImmediateDominator(self.handle, false); + + if block.is_null() { + return None; + } + + Some(Ref::new(BasicBlock::from_raw(block, self.context.clone()))) + } + } + + pub fn dominators(&self) -> Array> { + unsafe { + let mut count = 0; + let blocks = BNGetBasicBlockDominators(self.handle, &mut count, false); + + Array::new(blocks, count, self.context.clone()) + } + } + + pub fn strict_dominators(&self) -> Array> { + unsafe { + let mut count = 0; + let blocks = BNGetBasicBlockStrictDominators(self.handle, &mut count, false); + + Array::new(blocks, count, self.context.clone()) + } + } + + pub fn dominator_tree_children(&self) -> Array> { + unsafe { + let mut count = 0; + let blocks = BNGetBasicBlockDominatorTreeChildren(self.handle, &mut count, false); + + Array::new(blocks, count, self.context.clone()) + } + } + + pub fn dominance_frontier(&self) -> Array> { + unsafe { + let mut count = 0; + let blocks = BNGetBasicBlockDominanceFrontier(self.handle, &mut count, false); + + Array::new(blocks, count, self.context.clone()) + } + } + + // TODO iterated dominance frontier + +} + +impl<'a, C: BlockContext> IntoIterator for &'a BasicBlock { + type Item = C::Instruction; + type IntoIter = C::Iter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl fmt::Debug for BasicBlock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, " {}>", self.handle, &self.context, self.raw_start(), self.raw_end()) + } +} + +impl ToOwned for BasicBlock { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for BasicBlock { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: BNNewBasicBlockReference(handle.handle), + context: handle.context.clone(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeBasicBlock(handle.handle); + } +} + +unsafe impl CoreOwnedArrayProvider for BasicBlock { + type Raw = *mut BNBasicBlock; + type Context = C; + + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeBasicBlockList(raw, count); + } +} + +unsafe impl<'a, C: 'a + BlockContext> CoreOwnedArrayWrapper<'a> for BasicBlock { + type Wrapped = Guard<'a, BasicBlock>; + + unsafe fn wrap_raw(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped { + Guard::new(BasicBlock::from_raw(*raw, context.clone()), context) + } +} + -- cgit v1.3.1