binaryninja/
component.rs

1use crate::binary_view::{BinaryView, BinaryViewExt};
2use crate::function::Function;
3use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
4use crate::string::{BnString, IntoCStr};
5use crate::types::ComponentReferencedType;
6use std::ffi::c_char;
7use std::fmt::Debug;
8use std::ptr::NonNull;
9
10use crate::variable::DataVariable;
11use binaryninjacore_sys::*;
12
13pub struct ComponentBuilder {
14    view: Ref<BinaryView>,
15    parent: Option<String>,
16    name: Option<String>,
17}
18
19impl ComponentBuilder {
20    pub fn new(view: Ref<BinaryView>) -> Self {
21        Self {
22            view,
23            parent: None,
24            name: None,
25        }
26    }
27
28    pub fn parent(mut self, parent_guid: impl Into<String>) -> Self {
29        self.parent = Some(parent_guid.into());
30        self
31    }
32
33    pub fn name(mut self, name: impl Into<String>) -> Self {
34        self.name = Some(name.into());
35        self
36    }
37
38    pub fn finalize(self) -> Ref<Component> {
39        let result = match (&self.parent, &self.name) {
40            (None, None) => unsafe { BNCreateComponent(self.view.handle) },
41            (None, Some(name)) => {
42                let name_raw = name.to_cstr();
43                unsafe {
44                    BNCreateComponentWithName(self.view.handle, name_raw.as_ptr() as *mut c_char)
45                }
46            }
47            (Some(guid), None) => {
48                let guid_raw = guid.to_cstr();
49                unsafe {
50                    BNCreateComponentWithParent(self.view.handle, guid_raw.as_ptr() as *mut c_char)
51                }
52            }
53            (Some(guid), Some(name)) => {
54                let guid_raw = guid.to_cstr();
55                let name_raw = name.to_cstr();
56                unsafe {
57                    BNCreateComponentWithParentAndName(
58                        self.view.handle,
59                        guid_raw.as_ptr() as *mut c_char,
60                        name_raw.as_ptr() as *mut c_char,
61                    )
62                }
63            }
64        };
65        unsafe { Component::ref_from_raw(NonNull::new(result).unwrap()) }
66    }
67}
68
69/// Components are objects that can contain Functions, Data Variables, and other Components.
70///
71/// They can be queried for information about the items contained within them.
72///
73/// Components have a Guid, which persistent across saves and loads of the database, and should be
74/// used for retrieving components when such is required and a reference to the Component cannot be held.
75#[repr(transparent)]
76pub struct Component {
77    pub(crate) handle: NonNull<BNComponent>,
78}
79
80impl Component {
81    pub(crate) unsafe fn from_raw(handle: NonNull<BNComponent>) -> Self {
82        Self { handle }
83    }
84
85    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNComponent>) -> Ref<Self> {
86        Ref::new(Self { handle })
87    }
88
89    pub fn guid(&self) -> String {
90        let result = unsafe { BNComponentGetGuid(self.handle.as_ptr()) };
91        assert!(!result.is_null());
92        unsafe { BnString::into_string(result) }
93    }
94
95    /// Add function to this component.
96    pub fn add_function(&self, func: &Function) -> bool {
97        unsafe { BNComponentAddFunctionReference(self.handle.as_ptr(), func.handle) }
98    }
99
100    /// Check whether this component contains a function.
101    pub fn contains_function(&self, func: &Function) -> bool {
102        unsafe { BNComponentContainsFunction(self.handle.as_ptr(), func.handle) }
103    }
104
105    /// Remove function from this component.
106    pub fn remove_function(&self, func: &Function) -> bool {
107        unsafe { BNComponentRemoveFunctionReference(self.handle.as_ptr(), func.handle) }
108    }
109
110    /// Move component to this component. This will remove it from the old parent.
111    pub fn add_component(&self, component: &Component) -> bool {
112        unsafe { BNComponentAddComponent(self.handle.as_ptr(), component.handle.as_ptr()) }
113    }
114
115    /// Check whether this component contains a component.
116    pub fn contains_component(&self, component: &Component) -> bool {
117        unsafe { BNComponentContainsComponent(self.handle.as_ptr(), component.handle.as_ptr()) }
118    }
119
120    /// Remove a component from the current component, moving it to the root.
121    ///
122    /// This function has no effect when used from the root component.
123    /// Use `BinaryView.remove_component` to Remove a component from the tree entirely.
124    pub fn remove_component(&self, component: &Component) -> bool {
125        self.view()
126            .unwrap()
127            .root_component()
128            .unwrap()
129            .add_component(component)
130    }
131
132    /// Add data variable to this component.
133    pub fn add_data_variable(&self, data_variable: &DataVariable) -> bool {
134        unsafe { BNComponentAddDataVariable(self.handle.as_ptr(), data_variable.address) }
135    }
136
137    /// Check whether this component contains a data variable.
138    pub fn contains_data_variable(&self, data_variable: &DataVariable) -> bool {
139        unsafe { BNComponentContainsDataVariable(self.handle.as_ptr(), data_variable.address) }
140    }
141
142    /// Remove data variable from this component.
143    pub fn remove_data_variable(&self, data_variable: &DataVariable) -> bool {
144        unsafe { BNComponentRemoveDataVariable(self.handle.as_ptr(), data_variable.address) }
145    }
146
147    /// Original name of the component
148    pub fn display_name(&self) -> String {
149        let result = unsafe { BNComponentGetDisplayName(self.handle.as_ptr()) };
150        assert!(!result.is_null());
151        unsafe { BnString::into_string(result) }
152    }
153
154    /// Original name set for this component
155    /// :note: The `.display_name` property should be used for `bv.get_component_by_path()` lookups.
156    /// This can differ from the .display_name property if one of its sibling components has the same .original_name; In that
157    /// case, .name will be an automatically generated unique name (e.g. "MyComponentName (1)") while .original_name will
158    /// remain what was originally set (e.g. "MyComponentName")
159    /// If this component has a duplicate name and is moved to a component where none of its siblings share its name,
160    /// .name will return the original "MyComponentName"
161    pub fn name(&self) -> String {
162        let result = unsafe { BNComponentGetOriginalName(self.handle.as_ptr()) };
163        assert!(!result.is_null());
164        unsafe { BnString::into_string(result) }
165    }
166
167    pub fn set_name(&self, name: &str) {
168        let name = name.to_cstr();
169        unsafe { BNComponentSetName(self.handle.as_ptr(), name.as_ptr()) }
170    }
171
172    /// The component that contains this component, if it exists.
173    pub fn parent(&self) -> Option<Ref<Component>> {
174        let result = unsafe { BNComponentGetParent(self.handle.as_ptr()) };
175        NonNull::new(result).map(|h| unsafe { Self::ref_from_raw(h) })
176    }
177
178    pub fn view(&self) -> Option<Ref<BinaryView>> {
179        let result = unsafe { BNComponentGetView(self.handle.as_ptr()) };
180        (!result.is_null()).then(|| unsafe { BinaryView::ref_from_raw(result) })
181    }
182
183    /// Is an iterator for all Components contained within this Component
184    pub fn components(&self) -> Array<Component> {
185        let mut count = 0;
186        let result = unsafe { BNComponentGetContainedComponents(self.handle.as_ptr(), &mut count) };
187        assert!(!result.is_null());
188        unsafe { Array::new(result, count, ()) }
189    }
190
191    /// List of all Functions contained within this Component
192    pub fn functions(&self) -> Array<Function> {
193        let mut count = 0;
194        let result = unsafe { BNComponentGetContainedFunctions(self.handle.as_ptr(), &mut count) };
195        assert!(!result.is_null());
196        unsafe { Array::new(result, count, ()) }
197    }
198
199    /// List of all Data Variables contained within this Component
200    pub fn data_variables(&self) -> Array<DataVariable> {
201        let mut count = 0;
202        let result =
203            unsafe { BNComponentGetContainedDataVariables(self.handle.as_ptr(), &mut count) };
204        assert!(!result.is_null());
205        unsafe { Array::new(result, count, ()) }
206    }
207
208    /// Get data variables referenced by this component
209    ///
210    /// * `recursive` - Get all DataVariables referenced by this component and subcomponents.
211    pub fn referenced_data_variables(&self, recursive: bool) -> Array<DataVariable> {
212        let mut count = 0;
213        let result = if recursive {
214            unsafe {
215                BNComponentGetReferencedDataVariablesRecursive(self.handle.as_ptr(), &mut count)
216            }
217        } else {
218            unsafe { BNComponentGetReferencedDataVariables(self.handle.as_ptr(), &mut count) }
219        };
220        unsafe { Array::new(result, count, ()) }
221    }
222
223    /// Get Types referenced by this component
224    ///
225    /// * `recursive` - Get all Types referenced by this component and subcomponents.
226    pub fn referenced_types(&self, recursive: bool) -> Array<ComponentReferencedType> {
227        let mut count = 0;
228        let result = if recursive {
229            unsafe { BNComponentGetReferencedTypesRecursive(self.handle.as_ptr(), &mut count) }
230        } else {
231            unsafe { BNComponentGetReferencedTypes(self.handle.as_ptr(), &mut count) }
232        };
233        unsafe { Array::new(result, count, ()) }
234    }
235
236    pub fn remove_all_functions(&self) {
237        unsafe { BNComponentRemoveAllFunctions(self.handle.as_ptr()) }
238    }
239
240    pub fn add_all_members_from(&self, component: &Component) {
241        unsafe {
242            BNComponentAddAllMembersFromComponent(self.handle.as_ptr(), component.handle.as_ptr())
243        }
244    }
245}
246
247impl Debug for Component {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        f.debug_struct("Component")
250            .field("guid", &self.guid())
251            .field("display_name", &self.display_name())
252            .field("name", &self.name())
253            .field("components", &self.components().to_vec())
254            .finish()
255    }
256}
257
258impl PartialEq for Component {
259    fn eq(&self, other: &Self) -> bool {
260        unsafe { BNComponentsEqual(self.handle.as_ptr(), other.handle.as_ptr()) }
261    }
262
263    #[allow(clippy::partialeq_ne_impl)]
264    fn ne(&self, other: &Self) -> bool {
265        unsafe { BNComponentsNotEqual(self.handle.as_ptr(), other.handle.as_ptr()) }
266    }
267}
268
269impl Eq for Component {}
270
271impl ToOwned for Component {
272    type Owned = Ref<Self>;
273
274    fn to_owned(&self) -> Self::Owned {
275        unsafe { RefCountable::inc_ref(self) }
276    }
277}
278
279unsafe impl RefCountable for Component {
280    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
281        Ref::new(Self {
282            handle: NonNull::new(BNNewComponentReference(handle.handle.as_ptr())).unwrap(),
283        })
284    }
285
286    unsafe fn dec_ref(handle: &Self) {
287        BNFreeComponent(handle.handle.as_ptr());
288    }
289}
290
291impl CoreArrayProvider for Component {
292    type Raw = *mut BNComponent;
293    type Context = ();
294    type Wrapped<'a> = Guard<'a, Self>;
295}
296
297unsafe impl CoreArrayProviderInner for Component {
298    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
299        BNFreeComponents(raw, count)
300    }
301
302    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
303        let raw_ptr = NonNull::new(*raw).unwrap();
304        Guard::new(Self::from_raw(raw_ptr), context)
305    }
306}