Skip to content
Open
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 base/strong_typedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <compare> // IWYU pragma: keep
#include <stddef.h>
#include <concepts>
#include <functional>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -89,6 +90,8 @@
// Hashable usable as a key in std and absl hash containers
// Formattable formattable with fmt, forwarding format specs such as {:#x} to the
// underlying type's formatter
// FfiWrapper implicit conversion to and from a C-style wrapper structure through
// the specified member, without making the underlying type implicit
// NonExtractable removes the explicit operator T() and the Value() accessor, so the
// underlying value can be constructed but never read back out. Every
// other modifier continues to function as normal.
Expand All @@ -115,6 +118,25 @@ namespace detail {
template <typename Modifier, typename... Mods>
inline constexpr bool HasModifier = (std::is_same_v<Modifier, Mods> || ...);

template <typename Mod, typename Ffi, typename T>
concept FfiWrapperFor = requires(const Ffi& value) {
typename Mod::FfiType;
requires std::same_as<typename Mod::FfiType, Ffi>;
{ Mod::template FromFfi<T>(value) } -> std::same_as<T>;
};

template <typename Ffi, typename T, typename... Mods>
inline constexpr bool HasFfiWrapper = (FfiWrapperFor<Mods, Ffi, T> || ...);

template <typename T, typename Ffi, typename First, typename... Rest>
constexpr T FromFfi(const Ffi& value)
{
if constexpr (FfiWrapperFor<First, Ffi, T>)
return First::template FromFfi<T>(value);
else
return FromFfi<T, Ffi, Rest...>(value);
}

// Internal access to a StrongTypedef's underlying value so that modifiers have
// access to it even when NonExtractable is in use.
struct Access
Expand Down Expand Up @@ -409,6 +431,33 @@ struct Formattable
};
};

// Enables implicit conversion to and from a C-style wrapper structure whose selected
// member stores the StrongTypedef's underlying value. Conversion to the underlying type
// itself remains explicit.
template <typename Ffi, auto ValueMember>
struct FfiWrapper
{
using FfiType = Ffi;

template <typename T>
static constexpr T FromFfi(const Ffi& value)
{
return T(value.*ValueMember);
}

template <typename Self, typename T>
requires requires(Ffi ffi, const T& value) { ffi.*ValueMember = value; }
struct Apply
{
constexpr operator Ffi() const
{
Ffi result {};
result.*ValueMember = detail::Access::Get(static_cast<const Self&>(*this));
return result;
}
};
};

// Disable both the explicit operator T() and the Value() accessor.
// All other modifiers continue to function as normal.
struct NonExtractable
Expand Down Expand Up @@ -437,6 +486,13 @@ class BN_EMPTY_BASES StrongTypedef : public Mods::template Apply<StrongTypedef<T
{
}

template <typename Ffi>
requires detail::HasFfiWrapper<std::remove_cvref_t<Ffi>, T, Mods...>
constexpr StrongTypedef(Ffi&& value)
: m_value(detail::FromFfi<T, std::remove_cvref_t<Ffi>, Mods...>(value))
{
}

explicit constexpr operator T() const noexcept(std::is_nothrow_copy_constructible_v<T>)
requires (!detail::HasModifier<NonExtractable, Mods...>)
{
Expand Down
435 changes: 433 additions & 2 deletions binaryninjacore.h

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion rust/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ macro_rules! ffi_span {
}

macro_rules! new_id_type {
($name:ident, $inner_type:ty) => {
($(#[$meta:meta])* $name:ident, $inner_type:ty $(, $ffi_type:ty, $ffi_field:ident)?) => {
$(#[$meta])*
#[derive(std::fmt::Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct $name(pub $inner_type);

Expand All @@ -80,5 +81,19 @@ macro_rules! new_id_type {
write!(f, "{}", self.0)
}
}

$(
impl From<$ffi_type> for $name {
fn from(value: $ffi_type) -> Self {
Self(value.$ffi_field)
}
}

impl From<$name> for $ffi_type {
fn from(value: $name) -> Self {
Self { $ffi_field: value.0 }
}
}
)?
};
}
1 change: 1 addition & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub mod secrets_provider;
pub mod section;
pub mod segment;
pub mod settings;
pub mod similarity;
pub mod string;
pub mod string_detection;
pub mod symbol;
Expand Down
10 changes: 7 additions & 3 deletions rust/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ pub struct Settings {
}

impl Settings {
pub(crate) unsafe fn from_raw(handle: *mut BNSettings) -> Self {
Self { handle }
}

pub(crate) unsafe fn ref_from_raw(handle: *mut BNSettings) -> Ref<Self> {
debug_assert!(!handle.is_null());
Ref::new(Self { handle })
Expand Down Expand Up @@ -517,11 +521,11 @@ impl Settings {
unsafe { BNSettingsRegisterGroup(self.handle, group.as_ptr(), title.as_ptr()) }
}

pub fn register_setting_json(&self, group: &str, properties: &str) -> bool {
let group = group.to_cstr();
pub fn register_setting_json(&self, key: &str, properties: &str) -> bool {
let key = key.to_cstr();
let properties = properties.to_cstr();

unsafe { BNSettingsRegisterSetting(self.handle, group.as_ptr(), properties.as_ptr()) }
unsafe { BNSettingsRegisterSetting(self.handle, key.as_ptr(), properties.as_ptr()) }
}

// TODO: register_setting but type-safely turn it into json
Expand Down
196 changes: 196 additions & 0 deletions rust/src/similarity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
//! Function similarity providers, sessions, and result rendering.

use binaryninjacore_sys::{
BNSimilarityAnnotationType, BNSimilarityApplyStatus, BNSimilarityEntityId,
BNSimilarityEntityRef, BNSimilarityEntityType, BNSimilarityProviderId, BNSimilarityResultId,
BNSimilaritySessionCompletionQuery, BNSimilaritySessionId, BNSimilaritySessionNodeId,
BNSimilaritySessionResolverId, BNSimilarityViewType,
};

pub mod graph;
pub mod node;
pub mod provider;
pub mod render;
pub mod session;

pub use graph::*;
pub use node::*;
pub use provider::*;
pub use render::*;
pub use session::*;

/// The kind of object represented by a similarity entity.
pub type SimilarityEntityType = BNSimilarityEntityType;

/// The result of applying a similarity match.
pub type SimilarityApplyStatus = BNSimilarityApplyStatus;

/// The kind of view produced when rendering a result.
pub type SimilarityViewType = BNSimilarityViewType;

/// The change represented by a rendered address range.
pub type SimilarityAnnotationType = BNSimilarityAnnotationType;

new_id_type!(
/// Identifies an entity within a similarity session node.
SimilarityEntityId,
u32,
BNSimilarityEntityId,
value
);

new_id_type!(
/// Identifies a result within a similarity session node.
SimilarityResultId,
u64,
BNSimilarityResultId,
value
);

new_id_type!(
/// Identifies a similarity session node.
SimilaritySessionNodeId,
u32,
BNSimilaritySessionNodeId,
value
);

new_id_type!(
/// Identifies a similarity session.
SimilaritySessionId,
u32,
BNSimilaritySessionId,
value
);

new_id_type!(
/// Identifies a similarity provider instance.
SimilarityProviderId,
u32,
BNSimilarityProviderId,
value
);

new_id_type!(
/// Identifies a similarity resolver instance.
SimilaritySessionResolverId,
u32,
BNSimilaritySessionResolverId,
value
);

/// Chooses which similarity session completion data to read or update.
///
/// A query cannot select both a provider and a resolver. An empty query selects the whole session.
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
pub struct SimilaritySessionCompletionQuery {
node_id: Option<SimilaritySessionNodeId>,
provider_id: Option<SimilarityProviderId>,
resolver_id: Option<SimilaritySessionResolverId>,
}

impl SimilaritySessionCompletionQuery {
/// Selects the whole session.
pub fn for_session() -> Self {
Self::default()
}
/// Selects a node.
pub fn for_node(node_id: SimilaritySessionNodeId) -> Self {
Self {
node_id: Some(node_id),
..Self::default()
}
}
/// Selects a provider across the session.
pub fn for_provider(provider_id: SimilarityProviderId) -> Self {
Self {
provider_id: Some(provider_id),
..Self::default()
}
}
/// Selects a resolver across the session.
pub fn for_resolver(resolver_id: SimilaritySessionResolverId) -> Self {
Self {
resolver_id: Some(resolver_id),
..Self::default()
}
}
/// Selects a provider within the current selection.
pub fn with_provider(mut self, provider_id: SimilarityProviderId) -> Self {
self.provider_id = Some(provider_id);
self.resolver_id = None;
self
}
/// Selects a resolver within the current selection.
pub fn with_resolver(mut self, resolver_id: SimilaritySessionResolverId) -> Self {
self.provider_id = None;
self.resolver_id = Some(resolver_id);
self
}

/// Returns the selected node, if any.
pub fn node_id(&self) -> Option<SimilaritySessionNodeId> {
self.node_id
}

/// Returns the selected provider, if any.
pub fn provider_id(&self) -> Option<SimilarityProviderId> {
self.provider_id
}

/// Returns the selected resolver, if any.
pub fn resolver_id(&self) -> Option<SimilaritySessionResolverId> {
self.resolver_id
}
}

impl From<SimilaritySessionCompletionQuery> for BNSimilaritySessionCompletionQuery {
fn from(value: SimilaritySessionCompletionQuery) -> Self {
Self {
hasNodeId: value.node_id.is_some(),
nodeId: value.node_id.unwrap_or(SimilaritySessionNodeId(0)).into(),
hasProviderId: value.provider_id.is_some(),
providerId: value.provider_id.unwrap_or(SimilarityProviderId(0)).into(),
hasResolverId: value.resolver_id.is_some(),
resolverId: value
.resolver_id
.unwrap_or(SimilaritySessionResolverId(0))
.into(),
}
}
}

/// Identifies an entity within a session node.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct SimilarityEntityRef {
pub node_id: SimilaritySessionNodeId,
pub entity_id: SimilarityEntityId,
}

/// Information about an entity.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SimilarityEntityInfo {
pub entity_type: SimilarityEntityType,
/// The address of the entity within its [`crate::binary_view::BinaryView`].
pub address: u64,
/// The display name of the entity.
pub name: String,
}

impl From<BNSimilarityEntityRef> for SimilarityEntityRef {
fn from(value: BNSimilarityEntityRef) -> Self {
Self {
node_id: value.nodeId.into(),
entity_id: value.entityId.into(),
}
}
}

impl From<SimilarityEntityRef> for BNSimilarityEntityRef {
fn from(value: SimilarityEntityRef) -> Self {
Self {
nodeId: value.node_id.into(),
entityId: value.entity_id.into(),
}
}
}
Loading
Loading