Skip to main content

binaryninja/similarity/
render.rs

1use super::{SimilarityAnnotationType, SimilarityEntityRef, SimilarityViewType};
2use crate::binary_view::BinaryView;
3use crate::flowgraph::FlowGraph;
4use crate::function::{Function, FunctionViewType};
5use crate::linear_view::LinearViewObject;
6use crate::rc::{Ref, RefCountable};
7use crate::string::{BnString, IntoCStr};
8use binaryninjacore_sys::*;
9
10/// A graph or linear view used to display a similarity result.
11pub struct SimilarityView {
12    /// The group used to arrange related views.
13    pub group: String,
14    /// The kind of view stored in this entry.
15    pub view_type: SimilarityViewType,
16    /// The flow graph, when `view_type` is a graph.
17    pub graph: Option<Ref<FlowGraph>>,
18    /// The binary view backing a linear view.
19    pub data: Option<Ref<BinaryView>>,
20    /// The linear view object, when `view_type` is linear.
21    pub linear_view: Option<Ref<LinearViewObject>>,
22    /// The session entity for this view, if its renderer provided one.
23    pub entity: Option<SimilarityEntityRef>,
24}
25
26/// An added, removed, or changed address range `[start, end)`.
27#[derive(Debug, Copy, Clone, PartialEq, Eq)]
28pub struct SimilarityRangeAnnotation {
29    pub start: u64,
30    pub end: u64,
31    pub annotation_type: SimilarityAnnotationType,
32}
33
34/// Holds the views used to display a similarity result.
35pub struct SimilarityRenderContext {
36    pub(crate) handle: *mut BNSimilarityRenderContext,
37}
38
39impl SimilarityRenderContext {
40    /// Creates an empty render context.
41    pub fn new() -> Ref<Self> {
42        unsafe { Self::ref_from_raw(BNCreateSimilarityRenderContext()) }
43    }
44
45    pub unsafe fn from_raw(handle: *mut BNSimilarityRenderContext) -> Self {
46        Self { handle }
47    }
48
49    pub unsafe fn ref_from_raw(handle: *mut BNSimilarityRenderContext) -> Ref<Self> {
50        Ref::new(Self { handle })
51    }
52
53    /// Sets the function representation preferred by renderers writing to this context.
54    pub fn set_preferred_view_type(&self, view_type: FunctionViewType) {
55        let raw = FunctionViewType::into_raw(view_type);
56        unsafe { BNSimilarityRenderContextSetPreferredViewType(self.handle, raw) };
57        FunctionViewType::free_raw(raw);
58    }
59
60    /// Returns the function representation preferred by renderers writing to this context.
61    pub fn preferred_view_type(&self) -> FunctionViewType {
62        let type_ = unsafe { BNSimilarityRenderContextGetPreferredViewType(self.handle) };
63        let name = if type_ == BNFunctionGraphType::HighLevelLanguageRepresentationFunctionGraph {
64            unsafe { BNSimilarityRenderContextGetPreferredViewTypeName(self.handle) }
65        } else {
66            std::ptr::null_mut()
67        };
68        FunctionViewType::from_owned_raw(BNFunctionViewType { type_, name }).unwrap()
69    }
70
71    /// Adds a flow graph to a view group.
72    pub fn add_flow_graph(&self, group: &str, graph: &FlowGraph) {
73        let group = group.to_cstr();
74        unsafe { BNSimilarityRenderContextAddFlowGraph(self.handle, group.as_ptr(), graph.handle) }
75    }
76
77    /// Adds a flow graph for a session entity to a view group.
78    pub fn add_flow_graph_for_entity(
79        &self,
80        group: &str,
81        graph: &FlowGraph,
82        entity: SimilarityEntityRef,
83    ) {
84        let group = group.to_cstr();
85        let entity = BNSimilarityEntityRef::from(entity);
86        unsafe {
87            BNSimilarityRenderContextAddFlowGraphForEntity(
88                self.handle,
89                group.as_ptr(),
90                graph.handle,
91                &entity,
92            )
93        }
94    }
95
96    /// Adds a linear view to a view group.
97    pub fn add_linear_view(&self, group: &str, data: &BinaryView, linear_view: &LinearViewObject) {
98        let group = group.to_cstr();
99        unsafe {
100            BNSimilarityRenderContextAddLinearView(
101                self.handle,
102                group.as_ptr(),
103                data.handle,
104                linear_view.handle,
105            )
106        }
107    }
108
109    /// Adds a linear view for a session entity to a view group.
110    pub fn add_linear_view_for_entity(
111        &self,
112        group: &str,
113        data: &BinaryView,
114        linear_view: &LinearViewObject,
115        entity: SimilarityEntityRef,
116    ) {
117        let group = group.to_cstr();
118        let entity = BNSimilarityEntityRef::from(entity);
119        unsafe {
120            BNSimilarityRenderContextAddLinearViewForEntity(
121                self.handle,
122                group.as_ptr(),
123                data.handle,
124                linear_view.handle,
125                &entity,
126            )
127        }
128    }
129
130    /// Returns the views in insertion order.
131    pub fn views(&self) -> Vec<SimilarityView> {
132        let mut count = 0;
133        let raw = unsafe { BNGetSimilarityRenderContextViews(self.handle, &mut count) };
134        let views = unsafe { std::slice::from_raw_parts(raw, count) };
135        let result = views
136            .iter()
137            .map(|view| {
138                let view = *view;
139                let graph = unsafe { BNSimilarityViewGetFlowGraph(view) };
140                let data = unsafe { BNSimilarityViewGetLinearViewData(view) };
141                let linear_view = unsafe { BNSimilarityViewGetLinearView(view) };
142                let mut entity = std::mem::MaybeUninit::uninit();
143                let entity = unsafe { BNSimilarityViewGetEntity(view, entity.as_mut_ptr()) }
144                    .then(|| unsafe { entity.assume_init().into() });
145                SimilarityView {
146                    group: unsafe { BnString::into_string(BNSimilarityViewGetGroup(view)) },
147                    view_type: unsafe { BNSimilarityViewGetType(view) },
148                    graph: (!graph.is_null()).then(|| unsafe { FlowGraph::ref_from_raw(graph) }),
149                    data: (!data.is_null()).then(|| unsafe { BinaryView::ref_from_raw(data) }),
150                    linear_view: (!linear_view.is_null())
151                        .then(|| unsafe { LinearViewObject::ref_from_raw(linear_view) }),
152                    entity,
153                }
154            })
155            .collect();
156        unsafe { BNFreeSimilarityViewList(raw, count) };
157        result
158    }
159}
160
161impl ToOwned for SimilarityRenderContext {
162    type Owned = Ref<Self>;
163
164    fn to_owned(&self) -> Self::Owned {
165        unsafe { RefCountable::inc_ref(self) }
166    }
167}
168
169unsafe impl RefCountable for SimilarityRenderContext {
170    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
171        Ref::new(Self {
172            handle: BNNewSimilarityRenderContextReference(handle.handle),
173        })
174    }
175
176    unsafe fn dec_ref(handle: &Self) {
177        BNFreeSimilarityRenderContext(handle.handle)
178    }
179}
180
181/// Renders graph and linear views with range annotations.
182pub struct DiffRenderer {
183    handle: *mut BNDiffRenderer,
184}
185
186impl DiffRenderer {
187    /// Creates a renderer without annotations.
188    pub fn new() -> Ref<Self> {
189        unsafe {
190            Ref::new(Self {
191                handle: BNCreateDiffRenderer(),
192            })
193        }
194    }
195
196    /// Adds a range annotation to later renders.
197    ///
198    /// NOTE: Empty ranges are ignored.
199    pub fn add_range_annotation(&self, annotation: SimilarityRangeAnnotation) {
200        unsafe {
201            BNDiffRendererAddRangeAnnotation(
202                self.handle,
203                annotation.start,
204                annotation.end,
205                annotation.annotation_type,
206            )
207        }
208    }
209
210    /// Renders the graph and linear views for a function.
211    pub fn render_function(&self, context: &SimilarityRenderContext, function: &Function) {
212        unsafe { BNDiffRendererRenderFunction(self.handle, context.handle, function.handle) }
213    }
214
215    /// Renders graph and linear views for a function and session entity.
216    pub fn render_function_for_entity(
217        &self,
218        context: &SimilarityRenderContext,
219        function: &Function,
220        entity: SimilarityEntityRef,
221    ) {
222        let entity = BNSimilarityEntityRef::from(entity);
223        unsafe {
224            BNDiffRendererRenderFunctionForEntity(
225                self.handle,
226                context.handle,
227                function.handle,
228                &entity,
229            )
230        }
231    }
232
233    /// Renders an annotated flow graph.
234    pub fn render_flow_graph(
235        &self,
236        context: &SimilarityRenderContext,
237        group: &str,
238        graph: &FlowGraph,
239    ) {
240        let group = group.to_cstr();
241        unsafe {
242            BNDiffRendererRenderFlowGraph(self.handle, context.handle, group.as_ptr(), graph.handle)
243        }
244    }
245
246    /// Renders an annotated flow graph for a session entity.
247    pub fn render_flow_graph_for_entity(
248        &self,
249        context: &SimilarityRenderContext,
250        group: &str,
251        graph: &FlowGraph,
252        entity: SimilarityEntityRef,
253    ) {
254        let group = group.to_cstr();
255        let entity = BNSimilarityEntityRef::from(entity);
256        unsafe {
257            BNDiffRendererRenderFlowGraphForEntity(
258                self.handle,
259                context.handle,
260                group.as_ptr(),
261                graph.handle,
262                &entity,
263            )
264        }
265    }
266
267    /// Renders an annotated linear view.
268    pub fn render_linear_view(
269        &self,
270        context: &SimilarityRenderContext,
271        group: &str,
272        data: &BinaryView,
273        linear_view: &LinearViewObject,
274    ) {
275        let group = group.to_cstr();
276        unsafe {
277            BNDiffRendererRenderLinearView(
278                self.handle,
279                context.handle,
280                group.as_ptr(),
281                data.handle,
282                linear_view.handle,
283            )
284        }
285    }
286
287    /// Renders an annotated linear view for a session entity.
288    pub fn render_linear_view_for_entity(
289        &self,
290        context: &SimilarityRenderContext,
291        group: &str,
292        data: &BinaryView,
293        linear_view: &LinearViewObject,
294        entity: SimilarityEntityRef,
295    ) {
296        let group = group.to_cstr();
297        let entity = BNSimilarityEntityRef::from(entity);
298        unsafe {
299            BNDiffRendererRenderLinearViewForEntity(
300                self.handle,
301                context.handle,
302                group.as_ptr(),
303                data.handle,
304                linear_view.handle,
305                &entity,
306            )
307        }
308    }
309}
310
311impl ToOwned for DiffRenderer {
312    type Owned = Ref<Self>;
313
314    fn to_owned(&self) -> Self::Owned {
315        unsafe { RefCountable::inc_ref(self) }
316    }
317}
318
319unsafe impl RefCountable for DiffRenderer {
320    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
321        Ref::new(Self {
322            handle: BNNewDiffRendererReference(handle.handle),
323        })
324    }
325
326    unsafe fn dec_ref(handle: &Self) {
327        BNFreeDiffRenderer(handle.handle)
328    }
329}