summaryrefslogtreecommitdiff
path: root/rust/src/flowgraph
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/flowgraph')
-rw-r--r--rust/src/flowgraph/edge.rs113
-rw-r--r--rust/src/flowgraph/node.rs155
2 files changed, 268 insertions, 0 deletions
diff --git a/rust/src/flowgraph/edge.rs b/rust/src/flowgraph/edge.rs
new file mode 100644
index 00000000..7862f156
--- /dev/null
+++ b/rust/src/flowgraph/edge.rs
@@ -0,0 +1,113 @@
+use binaryninjacore_sys::*;
+
+use crate::flowgraph::node::FlowGraphNode;
+use crate::flowgraph::{BranchType, EdgePenStyle, ThemeColor};
+use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct FlowGraphEdge {
+ pub branch_type: BranchType,
+ pub target: Ref<FlowGraphNode>,
+ pub points: Vec<Point>,
+ pub back_edge: bool,
+ pub style: EdgeStyle,
+}
+
+impl FlowGraphEdge {
+ pub fn from_raw(value: &BNFlowGraphEdge) -> Self {
+ let raw_points = unsafe { std::slice::from_raw_parts(value.points, value.pointCount) };
+ let points: Vec<_> = raw_points.iter().copied().map(Point::from).collect();
+ Self {
+ branch_type: value.type_,
+ target: unsafe { FlowGraphNode::from_raw(value.target) }.to_owned(),
+ points,
+ back_edge: value.backEdge,
+ style: value.style.into(),
+ }
+ }
+}
+
+impl CoreArrayProvider for FlowGraphEdge {
+ type Raw = BNFlowGraphEdge;
+ type Context = ();
+ type Wrapped<'a> = FlowGraphEdge;
+}
+
+unsafe impl CoreArrayProviderInner for FlowGraphEdge {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) {
+ BNFreeFlowGraphNodeEdgeList(raw, count);
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Self::from_raw(raw)
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Default)]
+pub struct Point {
+ pub x: f32,
+ pub y: f32,
+}
+
+impl Point {
+ pub fn new(x: f32, y: f32) -> Self {
+ Self { x, y }
+ }
+}
+
+impl From<BNPoint> for Point {
+ fn from(value: BNPoint) -> Self {
+ Self {
+ x: value.x,
+ y: value.y,
+ }
+ }
+}
+
+impl From<Point> for BNPoint {
+ fn from(value: Point) -> Self {
+ Self {
+ x: value.x,
+ y: value.y,
+ }
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct EdgeStyle {
+ style: EdgePenStyle,
+ width: usize,
+ color: ThemeColor,
+}
+
+impl EdgeStyle {
+ pub fn new(style: EdgePenStyle, width: usize, color: ThemeColor) -> Self {
+ Self {
+ style,
+ width,
+ color,
+ }
+ }
+}
+
+impl Default for EdgeStyle {
+ fn default() -> Self {
+ Self::new(EdgePenStyle::SolidLine, 0, ThemeColor::AddressColor)
+ }
+}
+
+impl From<BNEdgeStyle> for EdgeStyle {
+ fn from(style: BNEdgeStyle) -> Self {
+ Self::new(style.style, style.width, style.color)
+ }
+}
+
+impl From<EdgeStyle> for BNEdgeStyle {
+ fn from(style: EdgeStyle) -> Self {
+ Self {
+ style: style.style,
+ width: style.width,
+ color: style.color,
+ }
+ }
+}
diff --git a/rust/src/flowgraph/node.rs b/rust/src/flowgraph/node.rs
new file mode 100644
index 00000000..5c2b9248
--- /dev/null
+++ b/rust/src/flowgraph/node.rs
@@ -0,0 +1,155 @@
+use crate::basic_block::{BasicBlock, BlockContext};
+use crate::disassembly::DisassemblyTextLine;
+use crate::flowgraph::edge::{EdgeStyle, FlowGraphEdge};
+use crate::flowgraph::{BranchType, FlowGraph};
+use crate::function::HighlightColor;
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
+use binaryninjacore_sys::*;
+use std::fmt::{Debug, Formatter};
+
+#[derive(PartialEq, Eq, Hash)]
+pub struct FlowGraphNode {
+ pub(crate) handle: *mut BNFlowGraphNode,
+}
+
+impl FlowGraphNode {
+ pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraphNode) -> Self {
+ Self { handle: raw }
+ }
+
+ pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraphNode) -> Ref<Self> {
+ Ref::new(Self { handle: raw })
+ }
+
+ pub fn new(graph: &FlowGraph) -> Ref<Self> {
+ unsafe { FlowGraphNode::ref_from_raw(BNCreateFlowGraphNode(graph.handle)) }
+ }
+
+ pub fn basic_block<C: BlockContext>(&self, context: C) -> Option<Ref<BasicBlock<C>>> {
+ let block_ptr = unsafe { BNGetFlowGraphBasicBlock(self.handle) };
+ if block_ptr.is_null() {
+ return None;
+ }
+ Some(unsafe { BasicBlock::ref_from_raw(block_ptr, context) })
+ }
+
+ pub fn set_basic_block<C: BlockContext>(&self, block: Option<&BasicBlock<C>>) {
+ match block {
+ Some(block) => unsafe { BNSetFlowGraphBasicBlock(self.handle, block.handle) },
+ None => unsafe { BNSetFlowGraphBasicBlock(self.handle, std::ptr::null_mut()) },
+ }
+ }
+
+ pub fn lines(&self) -> Array<DisassemblyTextLine> {
+ let mut count = 0;
+ let result = unsafe { BNGetFlowGraphNodeLines(self.handle, &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ pub fn set_lines(&self, lines: impl IntoIterator<Item = DisassemblyTextLine>) {
+ // NOTE: This will create allocations and increment tag refs, we must call DisassemblyTextLine::free_raw
+ let mut raw_lines: Vec<BNDisassemblyTextLine> = lines
+ .into_iter()
+ .map(DisassemblyTextLine::into_raw)
+ .collect();
+ unsafe {
+ BNSetFlowGraphNodeLines(self.handle, raw_lines.as_mut_ptr(), raw_lines.len());
+ for raw_line in raw_lines {
+ DisassemblyTextLine::free_raw(raw_line);
+ }
+ }
+ }
+
+ /// Returns the graph position of the node in X, Y form.
+ pub fn position(&self) -> (i32, i32) {
+ let pos_x = unsafe { BNGetFlowGraphNodeX(self.handle) };
+ let pos_y = unsafe { BNGetFlowGraphNodeY(self.handle) };
+ (pos_x, pos_y)
+ }
+
+ /// Sets the graph position of the node.
+ pub fn set_position(&self, x: i32, y: i32) {
+ unsafe { BNFlowGraphNodeSetX(self.handle, x) };
+ unsafe { BNFlowGraphNodeSetY(self.handle, y) };
+ }
+
+ pub fn highlight_color(&self) -> HighlightColor {
+ let raw = unsafe { BNGetFlowGraphNodeHighlight(self.handle) };
+ HighlightColor::from(raw)
+ }
+
+ pub fn set_highlight_color(&self, highlight: HighlightColor) {
+ unsafe { BNSetFlowGraphNodeHighlight(self.handle, highlight.into()) };
+ }
+
+ pub fn incoming_edges(&self) -> Array<FlowGraphEdge> {
+ let mut count = 0;
+ let result = unsafe { BNGetFlowGraphNodeIncomingEdges(self.handle, &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ pub fn outgoing_edges(&self) -> Array<FlowGraphEdge> {
+ let mut count = 0;
+ let result = unsafe { BNGetFlowGraphNodeOutgoingEdges(self.handle, &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ /// Connects two flow graph nodes with an edge.
+ pub fn add_outgoing_edge(
+ &self,
+ type_: BranchType,
+ target: &FlowGraphNode,
+ edge_style: EdgeStyle,
+ ) {
+ unsafe {
+ BNAddFlowGraphNodeOutgoingEdge(self.handle, type_, target.handle, edge_style.into())
+ }
+ }
+}
+
+impl Debug for FlowGraphNode {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("FlowGraphNode")
+ .field("lines", &self.lines().to_vec())
+ .finish()
+ }
+}
+
+unsafe impl RefCountable for FlowGraphNode {
+ unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
+ Ref::new(Self {
+ handle: BNNewFlowGraphNodeReference(handle.handle),
+ })
+ }
+
+ unsafe fn dec_ref(handle: &Self) {
+ BNFreeFlowGraphNode(handle.handle);
+ }
+}
+
+impl ToOwned for FlowGraphNode {
+ type Owned = Ref<Self>;
+
+ fn to_owned(&self) -> Self::Owned {
+ unsafe { RefCountable::inc_ref(self) }
+ }
+}
+
+impl CoreArrayProvider for FlowGraphNode {
+ type Raw = *mut BNFlowGraphNode;
+ type Context = ();
+ type Wrapped<'a> = Guard<'a, FlowGraphNode>;
+}
+
+unsafe impl CoreArrayProviderInner for FlowGraphNode {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) {
+ BNFreeFlowGraphNodeList(raw, count);
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Guard::new(Self::from_raw(*raw), context)
+ }
+}