Skip to content

Commit 99e0985

Browse files
committed
Add Render Layer API to Rust
1 parent 9099142 commit 99e0985

File tree

13 files changed

+817
-56
lines changed

13 files changed

+817
-56
lines changed

rust/src/basic_block.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::BranchType;
1919
use binaryninjacore_sys::*;
2020
use std::fmt;
2121
use std::fmt::Debug;
22+
use std::hash::{Hash, Hasher};
2223

2324
enum EdgeDirection {
2425
Incoming,
@@ -97,7 +98,14 @@ pub trait BlockContext: Clone + Sync + Send + Sized {
9798
fn iter(&self, block: &BasicBlock<Self>) -> Self::Iter;
9899
}
99100

100-
#[derive(PartialEq, Eq, Hash)]
101+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
102+
pub enum BasicBlockType {
103+
Native,
104+
LowLevelIL,
105+
MediumLevelIL,
106+
HighLevelIL,
107+
}
108+
101109
pub struct BasicBlock<C: BlockContext> {
102110
pub(crate) handle: *mut BNBasicBlock,
103111
context: C,
@@ -127,6 +135,19 @@ impl<C: BlockContext> BasicBlock<C> {
127135
}
128136
}
129137

138+
pub fn block_type(&self) -> BasicBlockType {
139+
if unsafe { !BNIsILBasicBlock(self.handle) } {
140+
BasicBlockType::Native
141+
} else if unsafe { BNIsLowLevelILBasicBlock(self.handle) } {
142+
BasicBlockType::LowLevelIL
143+
} else if unsafe { BNIsMediumLevelILBasicBlock(self.handle) } {
144+
BasicBlockType::MediumLevelIL
145+
} else {
146+
// We checked all other IL levels, so this is safe.
147+
BasicBlockType::HighLevelIL
148+
}
149+
}
150+
130151
pub fn iter(&self) -> C::Iter {
131152
self.context.iter(self)
132153
}
@@ -194,7 +215,7 @@ impl<C: BlockContext> BasicBlock<C> {
194215
if block.is_null() {
195216
return None;
196217
}
197-
Some(Ref::new(BasicBlock::from_raw(block, self.context.clone())))
218+
Some(BasicBlock::ref_from_raw(block, self.context.clone()))
198219
}
199220
}
200221

@@ -237,6 +258,24 @@ impl<C: BlockContext> BasicBlock<C> {
237258
// TODO iterated dominance frontier
238259
}
239260

261+
impl<C: BlockContext> Hash for BasicBlock<C> {
262+
fn hash<H: Hasher>(&self, state: &mut H) {
263+
self.function().hash(state);
264+
self.block_type().hash(state);
265+
state.write_usize(self.index());
266+
}
267+
}
268+
269+
impl<C: BlockContext> PartialEq for BasicBlock<C> {
270+
fn eq(&self, other: &Self) -> bool {
271+
self.function() == other.function()
272+
&& self.index() == other.index()
273+
&& self.block_type() == other.block_type()
274+
}
275+
}
276+
277+
impl<C: BlockContext> Eq for BasicBlock<C> {}
278+
240279
impl<C: BlockContext> IntoIterator for &BasicBlock<C> {
241280
type Item = C::Instruction;
242281
type IntoIter = C::Iter;

rust/src/binary_view.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,8 +1209,8 @@ pub trait BinaryViewExt: BinaryViewBase {
12091209

12101210
/// Retrieves a list of the next disassembly lines.
12111211
///
1212-
/// `get_next_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the
1213-
/// next disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called
1212+
/// Retrieves an [`Array`] over [`LinearDisassemblyLine`] objects for the
1213+
/// next disassembly lines, and updates the [`LinearViewCursor`] passed in. This function can be called
12141214
/// repeatedly to get more lines of linear disassembly.
12151215
///
12161216
/// # Arguments

rust/src/collaboration/sync.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ pub fn is_type_archive_snapshot_ignored<S: BnStrCompatible>(
701701
pub fn download_type_archive<S: BnStrCompatible>(
702702
file: &RemoteFile,
703703
location: S,
704-
) -> Result<Option<TypeArchive>, ()> {
704+
) -> Result<Option<Ref<TypeArchive>>, ()> {
705705
download_type_archive_with_progress(file, location, NoProgressCallback)
706706
}
707707

@@ -711,7 +711,7 @@ pub fn download_type_archive_with_progress<S: BnStrCompatible, F: ProgressCallba
711711
file: &RemoteFile,
712712
location: S,
713713
mut progress: F,
714-
) -> Result<Option<TypeArchive>, ()> {
714+
) -> Result<Option<Ref<TypeArchive>>, ()> {
715715
let mut value = std::ptr::null_mut();
716716
let db_path = location.into_bytes_with_nul();
717717
let success = unsafe {
@@ -724,7 +724,7 @@ pub fn download_type_archive_with_progress<S: BnStrCompatible, F: ProgressCallba
724724
)
725725
};
726726
success
727-
.then(|| NonNull::new(value).map(|handle| unsafe { TypeArchive::from_raw(handle) }))
727+
.then(|| NonNull::new(value).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }))
728728
.ok_or(())
729729
}
730730

rust/src/disassembly.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ pub type DisassemblyOption = BNDisassemblyOption;
3030
pub type InstructionTextTokenType = BNInstructionTextTokenType;
3131
pub type StringType = BNStringType;
3232

33-
#[derive(Clone, PartialEq, Debug, Default)]
33+
#[derive(Clone, PartialEq, Debug, Default, Eq)]
3434
pub struct DisassemblyTextLine {
3535
pub address: u64,
36+
// TODO: This is not always available.
3637
pub instruction_index: usize,
3738
pub tokens: Vec<InstructionTextToken>,
3839
pub highlight: HighlightColor,
@@ -234,7 +235,7 @@ impl DisassemblyTextLineTypeInfo {
234235
}
235236
}
236237

237-
#[derive(Debug, Clone, PartialEq)]
238+
#[derive(Debug, Clone, PartialEq, Eq)]
238239
pub struct InstructionTextToken {
239240
pub address: u64,
240241
pub text: String,
@@ -882,6 +883,8 @@ impl From<InstructionTextTokenKind> for BNInstructionTextTokenType {
882883
}
883884
}
884885

886+
impl Eq for InstructionTextTokenKind {}
887+
885888
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
886889
pub enum InstructionTextTokenContext {
887890
Normal,

rust/src/flowgraph.rs

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414

1515
//! Interfaces for creating and displaying pretty CFGs in Binary Ninja.
1616
17-
use binaryninjacore_sys::*;
18-
1917
use crate::disassembly::DisassemblyTextLine;
18+
use binaryninjacore_sys::*;
19+
use std::slice;
2020

2121
use crate::rc::*;
2222

23+
use crate::basic_block::{BasicBlock, BlockContext};
24+
use crate::function::HighlightColor;
25+
use crate::render_layer::CoreRenderLayer;
2326
use std::marker::PhantomData;
2427

2528
pub type BranchType = BNBranchType;
@@ -37,21 +40,89 @@ impl FlowGraph {
3740
Self { handle: raw }
3841
}
3942

43+
pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraph) -> Ref<Self> {
44+
Ref::new(Self { handle: raw })
45+
}
46+
4047
pub fn new() -> Ref<Self> {
41-
unsafe { Ref::new(FlowGraph::from_raw(BNCreateFlowGraph())) }
48+
unsafe { FlowGraph::ref_from_raw(BNCreateFlowGraph()) }
49+
}
50+
51+
pub fn nodes<'a>(&self) -> Vec<Ref<FlowGraphNode<'a>>> {
52+
let mut count: usize = 0;
53+
let nodes_ptr = unsafe { BNGetFlowGraphNodes(self.handle, &mut count as *mut usize) };
54+
55+
let nodes = unsafe { slice::from_raw_parts_mut(nodes_ptr, count) };
56+
57+
let mut result = vec![];
58+
result.reserve(count);
59+
60+
for i in 0..count {
61+
result.push(unsafe { RefCountable::inc_ref(&FlowGraphNode::from_raw(nodes[i])) });
62+
}
63+
64+
unsafe { BNFreeFlowGraphNodeList(nodes_ptr, count) };
65+
66+
result
67+
}
68+
69+
pub fn get_node<'a>(&self, i: usize) -> Option<Ref<FlowGraphNode<'a>>> {
70+
let node_ptr = unsafe { BNGetFlowGraphNode(self.handle, i) };
71+
if node_ptr.is_null() {
72+
None
73+
} else {
74+
Some(unsafe { Ref::new(FlowGraphNode::from_raw(node_ptr)) })
75+
}
76+
}
77+
78+
pub fn get_node_count(&self) -> usize {
79+
unsafe { BNGetFlowGraphNodeCount(self.handle) }
80+
}
81+
82+
pub fn has_nodes(&self) -> bool {
83+
unsafe { BNFlowGraphHasNodes(self.handle) }
4284
}
4385

4486
pub fn append(&self, node: &FlowGraphNode) -> usize {
4587
unsafe { BNAddFlowGraphNode(self.handle, node.handle) }
4688
}
4789

90+
pub fn replace(&self, index: usize, node: &FlowGraphNode) {
91+
unsafe { BNReplaceFlowGraphNode(self.handle, index, node.handle) }
92+
}
93+
94+
pub fn clear(&self) {
95+
unsafe { BNClearFlowGraphNodes(self.handle) }
96+
}
97+
4898
pub fn set_option(&self, option: FlowGraphOption, value: bool) {
4999
unsafe { BNSetFlowGraphOption(self.handle, option, value) }
50100
}
51101

52102
pub fn is_option_set(&self, option: FlowGraphOption) -> bool {
53103
unsafe { BNIsFlowGraphOptionSet(self.handle, option) }
54104
}
105+
106+
/// A list of the currently applied [`CoreRenderLayer`]'s
107+
pub fn render_layers(&self) -> Array<CoreRenderLayer> {
108+
let mut count: usize = 0;
109+
unsafe {
110+
let handles = BNGetFlowGraphRenderLayers(self.handle, &mut count);
111+
Array::new(handles, count, ())
112+
}
113+
}
114+
115+
/// Add a Render Layer to be applied to this [`FlowGraph`].
116+
///
117+
/// NOTE: Layers will be applied in the order in which they are added.
118+
pub fn add_render_layer(&self, layer: &CoreRenderLayer) {
119+
unsafe { BNAddFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
120+
}
121+
122+
/// Remove a Render Layer from being applied to this [`FlowGraph`].
123+
pub fn remove_render_layer(&self, layer: &CoreRenderLayer) {
124+
unsafe { BNRemoveFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
125+
}
55126
}
56127

57128
unsafe impl RefCountable for FlowGraph {
@@ -88,8 +159,37 @@ impl<'a> FlowGraphNode<'a> {
88159
}
89160
}
90161

91-
pub fn new(graph: &FlowGraph) -> Self {
92-
unsafe { FlowGraphNode::from_raw(BNCreateFlowGraphNode(graph.handle)) }
162+
pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraphNode) -> Ref<Self> {
163+
Ref::new(Self {
164+
handle: raw,
165+
_data: PhantomData,
166+
})
167+
}
168+
169+
pub fn new(graph: &FlowGraph) -> Ref<Self> {
170+
unsafe { FlowGraphNode::ref_from_raw(BNCreateFlowGraphNode(graph.handle)) }
171+
}
172+
173+
pub fn basic_block<C: BlockContext>(&self, context: C) -> Option<Ref<BasicBlock<C>>> {
174+
let block_ptr = unsafe { BNGetFlowGraphBasicBlock(self.handle) };
175+
if block_ptr.is_null() {
176+
return None;
177+
}
178+
Some(unsafe { BasicBlock::ref_from_raw(block_ptr, context) })
179+
}
180+
181+
pub fn set_basic_block<C: BlockContext>(&self, block: Option<&BasicBlock<C>>) {
182+
match block {
183+
Some(block) => unsafe { BNSetFlowGraphBasicBlock(self.handle, block.handle) },
184+
None => unsafe { BNSetFlowGraphBasicBlock(self.handle, std::ptr::null_mut()) },
185+
}
186+
}
187+
188+
pub fn lines(&self) -> Array<DisassemblyTextLine> {
189+
let mut count = 0;
190+
let result = unsafe { BNGetFlowGraphNodeLines(self.handle, &mut count) };
191+
assert!(!result.is_null());
192+
unsafe { Array::new(result, count, ()) }
93193
}
94194

95195
pub fn set_lines(&self, lines: impl IntoIterator<Item = DisassemblyTextLine>) {
@@ -106,6 +206,30 @@ impl<'a> FlowGraphNode<'a> {
106206
}
107207
}
108208

209+
/// Returns the graph position of the node in X, Y form.
210+
pub fn position(&self) -> (i32, i32) {
211+
let pos_x = unsafe { BNGetFlowGraphNodeX(self.handle) };
212+
let pos_y = unsafe { BNGetFlowGraphNodeY(self.handle) };
213+
(pos_x, pos_y)
214+
}
215+
216+
/// Sets the graph position of the node.
217+
pub fn set_position(&self, x: i32, y: i32) {
218+
unsafe { BNFlowGraphNodeSetX(self.handle, x) };
219+
unsafe { BNFlowGraphNodeSetX(self.handle, y) };
220+
}
221+
222+
pub fn highlight_color(&self) -> HighlightColor {
223+
let raw = unsafe { BNGetFlowGraphNodeHighlight(self.handle) };
224+
HighlightColor::from(raw)
225+
}
226+
227+
pub fn set_highlight_color(&self, highlight: HighlightColor) {
228+
unsafe { BNSetFlowGraphNodeHighlight(self.handle, highlight.into()) };
229+
}
230+
231+
// TODO: Add getters and setters for edges
232+
109233
pub fn add_outgoing_edge(
110234
&self,
111235
type_: BranchType,

rust/src/function.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl Iterator for NativeBlockIter {
128128
}
129129
}
130130

131-
#[derive(Clone)]
131+
#[derive(Clone, Debug, PartialEq, Eq)]
132132
pub struct NativeBlock {
133133
_priv: (),
134134
}
@@ -2346,7 +2346,7 @@ impl Function {
23462346
/// Flow graph of unresolved stack adjustments
23472347
pub fn unresolved_stack_adjustment_graph(&self) -> Option<Ref<FlowGraph>> {
23482348
let graph = unsafe { BNGetUnresolvedStackAdjustmentGraph(self.handle) };
2349-
(!graph.is_null()).then(|| unsafe { Ref::new(FlowGraph::from_raw(graph)) })
2349+
(!graph.is_null()).then(|| unsafe { FlowGraph::ref_from_raw(graph) })
23502350
}
23512351

23522352
pub fn create_graph(
@@ -2358,7 +2358,7 @@ impl Function {
23582358
let raw_view_type = FunctionViewType::into_raw(view_type);
23592359
let result = unsafe { BNCreateFunctionGraph(self.handle, raw_view_type, settings_raw) };
23602360
FunctionViewType::free_raw(raw_view_type);
2361-
unsafe { Ref::new(FlowGraph::from_raw(result)) }
2361+
unsafe { FlowGraph::ref_from_raw(result) }
23622362
}
23632363

23642364
pub fn parent_components(&self) -> Array<Component> {

rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub mod project;
6868
pub mod rc;
6969
pub mod references;
7070
pub mod relocation;
71+
pub mod render_layer;
7172
pub mod section;
7273
pub mod segment;
7374
pub mod settings;

0 commit comments

Comments
 (0)