use std::fmt;
use crate::architecture::CoreArchitecture;
use crate::function::Function;
use binaryninjacore_sys::*;
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>,
}
impl<'a, C: 'a + BlockContext> CoreArrayProvider for Edge<'a, C> {
type Raw = BNBasicBlockEdge;
type Context = EdgeContext<'a, C>;
type Wrapped<'b> = Edge<'b, C> where 'a: 'b;
}
unsafe impl<'a, C: 'a + BlockContext> CoreArrayProviderInner for Edge<'a, C> {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeBasicBlockEdgeList(raw, count);
}
unsafe fn wrap_raw<'b>(raw: &'b Self::Raw, context: &'b Self::Context) -> Self::Wrapped<'b> {
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,
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 }
}
pub fn function(&self) -> Ref<Function> {
unsafe {
let func = BNGetBasicBlockFunction(self.handle);
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,
},
)
}
}
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())
}
}
}
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);
}
}
impl<C: BlockContext> CoreArrayProvider for BasicBlock<C> {
type Raw = *mut BNBasicBlock;
type Context = C;
type Wrapped<'a> = Guard<'a, BasicBlock<C>> where C: 'a;
}
unsafe impl<C: BlockContext> CoreArrayProviderInner for BasicBlock<C> {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeBasicBlockList(raw, count);
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
Guard::new(BasicBlock::from_raw(*raw, context.clone()), context)
}
}