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.

4 changes: 2 additions & 2 deletions plugins/warp/src/cache/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::sync::{Arc, OnceLock, RwLock};
pub static CONTAINER_CACHE: OnceLock<DashMap<String, Arc<RwLock<Box<dyn Container>>>>> =
OnceLock::new();

pub fn for_cached_containers(f: impl Fn(&dyn Container)) {
pub fn for_cached_containers(mut f: impl FnMut(&dyn Container)) {
let containers_cache = CONTAINER_CACHE.get_or_init(Default::default);
for container in containers_cache.iter() {
if let Ok(guarded_container) = container.read() {
Expand All @@ -15,7 +15,7 @@ pub fn for_cached_containers(f: impl Fn(&dyn Container)) {
}
}

pub fn for_cached_containers_mut(f: impl Fn(&mut dyn Container)) {
pub fn for_cached_containers_mut(mut f: impl FnMut(&mut dyn Container)) {
let containers_cache = CONTAINER_CACHE.get_or_init(Default::default);
for container in containers_cache.iter() {
if let Ok(mut guarded_container) = container.write() {
Expand Down
7 changes: 6 additions & 1 deletion plugins/warp/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ use crate::container::network::{NetworkClient, NetworkContainer};
use crate::matcher::MatcherSettings;
use crate::plugin::render_layer::HighlightRenderLayer;
use crate::plugin::settings::PluginSettings;
use crate::plugin::similarity::WarpSimilarityProviderType;
use crate::{core_signature_dir, user_signature_dir};
use binaryninja::background_task::BackgroundTask;
use binaryninja::command::{register_command, register_command_for_function};
use binaryninja::is_ui_enabled;
use binaryninja::settings::{QueryOptions, Settings};
use binaryninja::similarity::register_similarity_provider;

mod ffi;
mod function;
mod load;
mod render_layer;
mod settings;
pub(crate) mod settings;
mod similarity;
mod workflow;

fn load_bundled_signatures() {
Expand Down Expand Up @@ -180,6 +183,8 @@ fn plugin_init() -> bool {
function::RemoveFunction {},
);

register_similarity_provider(WarpSimilarityProviderType);

true
}

Expand Down
9 changes: 4 additions & 5 deletions plugins/warp/src/plugin/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use binaryninja::interaction::{
use binaryninja::rc::Ref;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::thread;
use warp::WarpFile;

Expand Down Expand Up @@ -136,14 +135,14 @@ impl LoadSignatureFile {
};

// Verify we have not already loaded the file.
let already_exists = AtomicBool::new(false);
let mut already_exists = false;
for_cached_containers(|c| {
if let Ok(_) = c.source_path(&source_file_id) {
if c.source_path(&source_file_id).is_ok() {
// TODO: What happens if path differs? Warn?
already_exists.store(true, std::sync::atomic::Ordering::SeqCst);
already_exists = true;
}
});
if already_exists.load(std::sync::atomic::Ordering::SeqCst) {
if already_exists {
let res = show_message_box(
"Load again?",
"File already loaded, would you like to load it again?",
Expand Down
Loading
Loading