summaryrefslogtreecommitdiff
path: root/rust/src/basicblock.rs
diff options
context:
space:
mode:
authorRyan Snyder <ryan@vector35.com>2021-01-21 18:27:48 +0000
committerKyleMiles <krm504@nyu.edu>2021-01-21 19:06:55 +0000
commitd3140edec185f47235b9e4642bdd56d6c585a341 (patch)
treea61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/basicblock.rs
parentc0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (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.rs274
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)
+ }
+}
+