summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/src/binaryview.rs56
-rw-r--r--rust/src/component.rs276
-rw-r--r--rust/src/function.rs8
-rw-r--r--rust/src/lib.rs1
-rw-r--r--rust/src/types.rs18
5 files changed, 359 insertions, 0 deletions
diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs
index bf14580c..7da5a744 100644
--- a/rust/src/binaryview.rs
+++ b/rust/src/binaryview.rs
@@ -33,6 +33,7 @@ use std::{ops, slice};
use crate::architecture::Architecture;
use crate::architecture::CoreArchitecture;
use crate::basicblock::BasicBlock;
+use crate::component::{Component, ComponentBuilder, IntoComponentGuid};
use crate::databuffer::DataBuffer;
use crate::debuginfo::DebugInfo;
use crate::fileaccessor::FileAccessor;
@@ -1373,6 +1374,61 @@ pub trait BinaryViewExt: BinaryViewBase {
Array::new(handle, count, ())
}
}
+
+ fn component_by_guid<S: BnStrCompatible>(&self, guid: S) -> Option<Component> {
+ let name = guid.into_bytes_with_nul();
+ let result = unsafe {
+ BNGetComponentByGuid(
+ self.as_ref().handle,
+ name.as_ref().as_ptr() as *const core::ffi::c_char,
+ )
+ };
+ core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) })
+ }
+
+ fn root_component(&self) -> Option<Component> {
+ let result = unsafe { BNGetRootComponent(self.as_ref().handle) };
+ core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) })
+ }
+
+ fn component_builder(&self) -> ComponentBuilder {
+ ComponentBuilder::new_from_raw(self.as_ref().handle)
+ }
+
+ fn component_by_path<P: BnStrCompatible>(&self, path: P) -> Option<Component> {
+ let path = path.into_bytes_with_nul();
+ let result = unsafe {
+ BNGetComponentByPath(
+ self.as_ref().handle,
+ path.as_ref().as_ptr() as *const core::ffi::c_char,
+ )
+ };
+ core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) })
+ }
+
+ fn remove_component(&self, component: &Component) -> bool {
+ unsafe { BNRemoveComponent(self.as_ref().handle, component.as_raw()) }
+ }
+
+ fn remove_component_by_guid<P: IntoComponentGuid>(&self, guid: P) -> bool {
+ let path = guid.component_guid();
+ unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) }
+ }
+
+ fn data_variable_parent_components(
+ &self,
+ data_variable: &DataVariable,
+ ) -> Array<Component> {
+ let mut count = 0;
+ let result = unsafe {
+ BNGetDataVariableParentComponents(
+ self.as_ref().handle,
+ data_variable.address(),
+ &mut count,
+ )
+ };
+ unsafe { Array::new(result, count, ()) }
+ }
}
impl<T: BinaryViewBase> BinaryViewExt for T {}
diff --git a/rust/src/component.rs b/rust/src/component.rs
new file mode 100644
index 00000000..e17efabf
--- /dev/null
+++ b/rust/src/component.rs
@@ -0,0 +1,276 @@
+use core::{ffi, mem, ptr};
+
+use crate::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt};
+use crate::function::Function;
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
+use crate::string::{BnStrCompatible, BnString};
+use crate::types::{ComponentReferencedTypes, DataVariable};
+
+use binaryninjacore_sys::*;
+
+pub struct ComponentBuilder {
+ bv: *mut BNBinaryView,
+ parent: Option<BnString>,
+ name: Option<BnString>,
+}
+
+impl ComponentBuilder {
+ pub(crate) fn new_from_raw(bv: *mut BNBinaryView) -> Self {
+ Self {
+ bv,
+ parent: None,
+ name: None,
+ }
+ }
+ pub fn new<I: BinaryViewBase>(bv: &I) -> Self {
+ Self {
+ bv: bv.as_ref().handle,
+ parent: None,
+ name: None,
+ }
+ }
+
+ pub fn parent<G: IntoComponentGuid>(mut self, parent: G) -> Self {
+ self.parent = Some(parent.component_guid());
+ self
+ }
+
+ pub fn name<S: BnStrCompatible>(mut self, name: S) -> Self {
+ self.name = Some(BnString::new(name));
+ self
+ }
+
+ pub fn finalize(self) -> Component {
+ let result = match (&self.parent, &self.name) {
+ (None, None) => unsafe { BNCreateComponent(self.bv) },
+ (None, Some(name)) => unsafe { BNCreateComponentWithName(self.bv, name.as_ptr()) },
+ (Some(guid), None) => unsafe { BNCreateComponentWithParent(self.bv, guid.as_ptr()) },
+ (Some(guid), Some(name)) => unsafe {
+ BNCreateComponentWithParentAndName(self.bv, guid.as_ptr(), name.as_ptr())
+ },
+ };
+ unsafe { Component::from_raw(ptr::NonNull::new(result).unwrap()) }
+ }
+}
+
+/// Components are objects that can contain Functions and other Components.
+///
+/// They can be queried for information about the functions contained within them.
+///
+/// Components have a Guid, which persistent across saves and loads of the database, and should be
+/// used for retrieving components when such is required and a reference to the Component cannot be held.
+#[repr(transparent)]
+pub struct Component {
+ handle: ptr::NonNull<BNComponent>,
+}
+
+impl Component {
+ #[allow(clippy::mut_from_ref)]
+ pub(crate) unsafe fn as_raw(&self) -> &mut BNComponent {
+ &mut *self.handle.as_ptr()
+ }
+
+ pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNComponent>) -> Self {
+ Self { handle }
+ }
+
+ pub(crate) unsafe fn ref_from_raw(handle: &*mut BNComponent) -> &Self {
+ assert!(!handle.is_null());
+ mem::transmute(handle)
+ }
+
+ pub fn guid(&self) -> BnString {
+ let result = unsafe { BNComponentGetGuid(self.as_raw()) };
+ assert!(!result.is_null());
+ unsafe { BnString::from_raw(result) }
+ }
+
+ /// Add function to this component.
+ pub fn add_function(&self, func: &Function) -> bool {
+ unsafe { BNComponentAddFunctionReference(self.as_raw(), func.handle) }
+ }
+
+ /// Check whether this component contains a function.
+ pub fn contains_function(&self, func: &Function) -> bool {
+ unsafe { BNComponentContainsFunction(self.as_raw(), func.handle) }
+ }
+
+ /// Remove function from this component.
+ pub fn remove_function(&self, func: &Function) -> bool {
+ unsafe { BNComponentRemoveFunctionReference(self.as_raw(), func.handle) }
+ }
+
+ /// Move component to this component. This will remove it from the old parent.
+ pub fn add_component(&self, component: &Component) -> bool {
+ unsafe { BNComponentAddComponent(self.as_raw(), component.as_raw()) }
+ }
+
+ /// Check whether this component contains a component.
+ pub fn contains_component(&self, component: &Component) -> bool {
+ unsafe { BNComponentContainsComponent(self.as_raw(), component.as_raw()) }
+ }
+
+ /// Remove a component from the current component, moving it to the root.
+ ///
+ /// This function has no effect when used from the root component.
+ /// Use `BinaryView.remove_component` to Remove a component from the tree entirely.
+ pub fn remove_component(&self, component: &Component) -> bool {
+ self.view()
+ .unwrap()
+ .root_component()
+ .unwrap()
+ .add_component(component)
+ }
+
+ pub fn add_data_variable(&self, data_variable: &DataVariable) -> bool {
+ unsafe { BNComponentAddDataVariable(self.as_raw(), data_variable.address()) }
+ }
+
+ pub fn contains_data_variable(&self, data_variable: &DataVariable) -> bool {
+ unsafe { BNComponentContainsDataVariable(self.as_raw(), data_variable.address()) }
+ }
+
+ pub fn remove_data_variable(&self, data_variable: &DataVariable) -> bool {
+ unsafe { BNComponentRemoveDataVariable(self.as_raw(), data_variable.address()) }
+ }
+
+ /// Original Name of the component
+ pub fn display_name(&self) -> BnString {
+ let result = unsafe { BNComponentGetDisplayName(self.as_raw()) };
+ assert!(!result.is_null());
+ unsafe { BnString::from_raw(result) }
+ }
+
+ /// Original name set for this component
+
+ /// :note: The `.display_name` property should be used for `bv.get_component_by_path()` lookups.
+
+ /// This can differ from the .display_name property if one of its sibling components has the same .original_name; In that
+ /// case, .name will be an automatically generated unique name (e.g. "MyComponentName (1)") while .original_name will
+ /// remain what was originally set (e.g. "MyComponentName")
+
+ /// If this component has a duplicate name and is moved to a component where none of its siblings share its name,
+ /// the .name property will return the original "MyComponentName"
+ pub fn name(&self) -> BnString {
+ let result = unsafe { BNComponentGetOriginalName(self.as_raw()) };
+ assert!(!result.is_null());
+ unsafe { BnString::from_raw(result) }
+ }
+
+ pub fn set_name<S: BnStrCompatible>(&self, name: S) {
+ let name = name.into_bytes_with_nul();
+ unsafe { BNComponentSetName(self.as_raw(), name.as_ref().as_ptr() as *const ffi::c_char) }
+ }
+
+ /// The component that contains this component, if it exists.
+ pub fn parent(&self) -> Option<Component> {
+ let result = unsafe { BNComponentGetParent(self.as_raw()) };
+ ptr::NonNull::new(result).map(|h| unsafe { Self::from_raw(h) })
+ }
+
+ pub fn view(&self) -> Option<Ref<BinaryView>> {
+ let result = unsafe { BNComponentGetView(self.as_raw()) };
+ (!result.is_null()).then(|| unsafe { BinaryView::from_raw(result) })
+ }
+
+ /// Is an iterator for all Components contained within this Component
+ pub fn components(&self) -> Array<Component> {
+ let mut count = 0;
+ let result = unsafe { BNComponentGetContainedComponents(self.as_raw(), &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ /// List of all Functions contained within this Component
+ ///
+ /// <div class="warning">
+ ///
+ /// functions Should be used instead of this in any performance sensitive context.
+ ///
+ /// </div>
+ pub fn functions(&self) -> Array<Function> {
+ let mut count = 0;
+ let result = unsafe { BNComponentGetContainedFunctions(self.as_raw(), &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ pub fn data_variables(&self) -> Array<DataVariable> {
+ let mut count = 0;
+ let result = unsafe { BNComponentGetContainedDataVariables(self.as_raw(), &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ /// Get data variables referenced by this component
+ ///
+ /// * `recursive` - Get all DataVariables referenced by this component and subcomponents.
+ pub fn get_referenced_data_variables(&self, recursive: bool) -> Array<DataVariable> {
+ let mut count = 0;
+ let result = if recursive {
+ unsafe { BNComponentGetReferencedDataVariablesRecursive(self.as_raw(), &mut count) }
+ } else {
+ unsafe { BNComponentGetReferencedDataVariables(self.as_raw(), &mut count) }
+ };
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ /// Get Types referenced by this component
+ ///
+ /// * `recursive` - Get all Types referenced by this component and subcomponents.
+ pub fn get_referenced_types(&self, recursive: bool) -> Array<ComponentReferencedTypes> {
+ let mut count = 0;
+ let result = if recursive {
+ unsafe { BNComponentGetReferencedTypesRecursive(self.as_raw(), &mut count) }
+ } else {
+ unsafe { BNComponentGetReferencedTypes(self.as_raw(), &mut count) }
+ };
+ unsafe { Array::new(result, count, ()) }
+ }
+}
+
+impl Drop for Component {
+ fn drop(&mut self) {
+ unsafe { BNFreeComponent(self.as_raw()) }
+ }
+}
+
+impl Clone for Component {
+ fn clone(&self) -> Self {
+ unsafe {
+ Self::from_raw(ptr::NonNull::new(BNNewComponentReference(self.as_raw())).unwrap())
+ }
+ }
+}
+
+impl CoreArrayProvider for Component {
+ type Raw = *mut BNComponent;
+ type Context = ();
+ type Wrapped<'a> = &'a Self;
+}
+
+unsafe impl CoreArrayProviderInner for Component {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeComponents(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Self::ref_from_raw(raw)
+ }
+}
+
+pub trait IntoComponentGuid {
+ fn component_guid(self) -> BnString;
+}
+
+impl IntoComponentGuid for &Component {
+ fn component_guid(self) -> BnString {
+ self.guid()
+ }
+}
+
+impl<S: BnStrCompatible> IntoComponentGuid for S {
+ fn component_guid(self) -> BnString {
+ BnString::new(self)
+ }
+}
diff --git a/rust/src/function.rs b/rust/src/function.rs
index 48f02205..bfd8b587 100644
--- a/rust/src/function.rs
+++ b/rust/src/function.rs
@@ -19,6 +19,7 @@ use crate::{
basicblock::{BasicBlock, BlockContext},
binaryview::{BinaryView, BinaryViewExt},
callingconvention::CallingConvention,
+ component::Component,
disassembly::{DisassemblySettings, DisassemblyTextLine},
flowgraph::FlowGraph,
hlil, llil,
@@ -2138,6 +2139,13 @@ impl Function {
let result = unsafe { BNCreateFunctionGraph(self.handle, graph_type, settings_raw) };
unsafe { Ref::new(FlowGraph::from_raw(result)) }
}
+
+ pub fn parent_components(&self) -> Array<Component> {
+ let mut count = 0;
+ let result = unsafe{ BNGetFunctionParentComponents(self.view().handle, self.handle, &mut count) };
+ assert!(!result.is_null());
+ unsafe{ Array::new(result, count, ()) }
+ }
}
impl fmt::Debug for Function {
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index e7cf1320..71ae9091 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -137,6 +137,7 @@ pub mod databuffer;
pub mod debuginfo;
pub mod demangle;
pub mod disassembly;
+pub mod component;
pub mod downloadprovider;
pub mod fileaccessor;
pub mod filemetadata;
diff --git a/rust/src/types.rs b/rust/src/types.rs
index 9b2271d5..8fab75dc 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -1339,6 +1339,24 @@ impl ToOwned for Type {
}
}
+pub struct ComponentReferencedTypes;
+impl CoreArrayProvider for ComponentReferencedTypes{
+ type Raw= *mut BNType;
+ type Context= ();
+ type Wrapped<'a> = &'a Self;
+}
+
+unsafe impl CoreArrayProviderInner for ComponentReferencedTypes{
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNComponentFreeReferencedTypes(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ // SAFETY: BNType and Type are trasparent
+ core::mem::transmute(raw)
+ }
+}
+
///////////////////////
// FunctionParameter