Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement rust Component #5611

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions rust/src/binaryview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1362,6 +1363,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 {}
Expand Down
300 changes: 300 additions & 0 deletions rust/src/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
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, ()) }
}

pub fn remove_itself(&self) -> bool {
unsafe { BNComponentRemoveComponent(self.as_raw()) }
}

pub fn remove_all_functions(&self) {
unsafe { BNComponentRemoveAllFunctions(self.as_raw()) }
}

pub fn add_all_members(&self, component: &Component) {
unsafe { BNComponentAddAllMembersFromComponent(self.as_raw(), component.as_raw()) }
}
}

impl PartialEq for Component {
fn eq(&self, other: &Self) -> bool {
unsafe { BNComponentsEqual(self.as_raw(), other.as_raw()) }
}

fn ne(&self, other: &Self) -> bool {
unsafe { BNComponentsNotEqual(self.as_raw(), other.as_raw()) }
}
}

impl Eq for Component {}

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)
}
}
8 changes: 8 additions & 0 deletions rust/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
basicblock::{BasicBlock, BlockContext},
binaryview::{BinaryView, BinaryViewExt},
callingconvention::CallingConvention,
component::Component,
disassembly::{DisassemblySettings, DisassemblyTextLine},
flowgraph::FlowGraph,
hlil, llil,
Expand Down Expand Up @@ -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 {
Expand Down
Loading
Loading