diff options
| author | Ryan Snyder <ryan@vector35.com> | 2021-01-21 18:27:48 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:06:55 +0000 |
| commit | d3140edec185f47235b9e4642bdd56d6c585a341 (patch) | |
| tree | a61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/basicblock.rs | |
| parent | c0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (diff) | |
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
Diffstat (limited to 'rust/src/basicblock.rs')
| -rw-r--r-- | rust/src/basicblock.rs | 274 |
1 files changed, 274 insertions, 0 deletions
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<C>>, + target: Guard<'a, BasicBlock<C>>, +} + +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<C> { + &*self.source + } + + pub fn target(&self) -> &BasicBlock<C> { + &*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<C>, +} + +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<Item=Self::Instruction>; + + fn start(&self, block: &BasicBlock<Self>) -> Self::Instruction; + fn iter(&self, block: &BasicBlock<Self>) -> Self::Iter; +} + +#[derive(PartialEq, Eq, Hash)] +pub struct BasicBlock<C: BlockContext> { + pub(crate) handle: *mut BNBasicBlock, + context: C, +} + +unsafe impl<C: BlockContext> Send for BasicBlock<C> {} +unsafe impl<C: BlockContext> Sync for BasicBlock<C> {} + +impl<C: BlockContext> BasicBlock<C> { + 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<Function> { + 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<Edge<C>> { + 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<Edge<C>> { + 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<Ref<Self>> { + 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<BasicBlock<C>> { + 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<BasicBlock<C>> { + 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<BasicBlock<C>> { + 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<BasicBlock<C>> { + 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<C> { + type Item = C::Instruction; + type IntoIter = C::Iter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<C: fmt::Debug + BlockContext> fmt::Debug for BasicBlock<C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "<bb handle {:p} context {:?} contents: {} -> {}>", self.handle, &self.context, self.raw_start(), self.raw_end()) + } +} + +impl<C: BlockContext> ToOwned for BasicBlock<C> { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl<C: BlockContext> RefCountable for BasicBlock<C> { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewBasicBlockReference(handle.handle), + context: handle.context.clone(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeBasicBlock(handle.handle); + } +} + +unsafe impl<C: BlockContext> CoreOwnedArrayProvider for BasicBlock<C> { + 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<C> { + type Wrapped = Guard<'a, BasicBlock<C>>; + + unsafe fn wrap_raw(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped { + Guard::new(BasicBlock::from_raw(*raw, context.clone()), context) + } +} + |
