summaryrefslogtreecommitdiff
path: root/plugins/warp/src/plugin
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2026-03-03 07:57:33 -0800
committerMason Reed <35282038+emesare@users.noreply.github.com>2026-03-24 18:46:48 -0700
commit2c358e705bbde855b12780be86ef19501a62dfed (patch)
tree4f3012bdf36c9a0f7de4218790e6e1aa389621ba /plugins/warp/src/plugin
parent7877f7caa3535a7c477c911ddeafdf5bb14ebc14 (diff)
[WARP] Server-side constraint matching
Reduce networked functions by constraining on the returned set of functions on the server
Diffstat (limited to 'plugins/warp/src/plugin')
-rw-r--r--plugins/warp/src/plugin/ffi/container.rs8
-rw-r--r--plugins/warp/src/plugin/settings.rs6
-rw-r--r--plugins/warp/src/plugin/workflow.rs25
3 files changed, 31 insertions, 8 deletions
diff --git a/plugins/warp/src/plugin/ffi/container.rs b/plugins/warp/src/plugin/ffi/container.rs
index 79f45dcb..aa0c37d3 100644
--- a/plugins/warp/src/plugin/ffi/container.rs
+++ b/plugins/warp/src/plugin/ffi/container.rs
@@ -5,7 +5,8 @@ use crate::container::{
};
use crate::convert::{from_bn_type, to_bn_type};
use crate::plugin::ffi::{
- BNWARPContainer, BNWARPFunction, BNWARPFunctionGUID, BNWARPSource, BNWARPTarget, BNWARPTypeGUID,
+ BNWARPConstraintGUID, BNWARPContainer, BNWARPFunction, BNWARPFunctionGUID, BNWARPSource,
+ BNWARPTarget, BNWARPTypeGUID,
};
use binaryninja::architecture::CoreArchitecture;
use binaryninja::binary_view::BinaryView;
@@ -218,6 +219,8 @@ pub unsafe extern "C" fn BNWARPContainerFetchFunctions(
source_tags_count: usize,
guids: *const BNWARPFunctionGUID,
count: usize,
+ constraints: *const BNWARPConstraintGUID,
+ constraints_count: usize,
) {
let arc_container = ManuallyDrop::new(Arc::from_raw(container));
let Ok(container) = arc_container.read() else {
@@ -234,8 +237,9 @@ pub unsafe extern "C" fn BNWARPContainerFetchFunctions(
.collect();
let guids = unsafe { std::slice::from_raw_parts(guids, count) };
+ let constraints = unsafe { std::slice::from_raw_parts(constraints, constraints_count) };
- if let Err(e) = container.fetch_functions(&target, &source_tags, guids) {
+ if let Err(e) = container.fetch_functions(&target, &source_tags, guids, constraints) {
tracing::error!("Failed to fetch functions: {}", e);
}
}
diff --git a/plugins/warp/src/plugin/settings.rs b/plugins/warp/src/plugin/settings.rs
index 6469be0f..896bee7f 100644
--- a/plugins/warp/src/plugin/settings.rs
+++ b/plugins/warp/src/plugin/settings.rs
@@ -40,7 +40,7 @@ pub struct PluginSettings {
impl PluginSettings {
pub const ALLOWED_SOURCE_TAGS_DEFAULT: [&'static str; 2] = ["official", "trusted"];
pub const ALLOWED_SOURCE_TAGS_SETTING: &'static str = "warp.fetcher.allowedSourceTags";
- pub const FETCH_BATCH_SIZE_DEFAULT: usize = 100;
+ pub const FETCH_BATCH_SIZE_DEFAULT: usize = 10000;
pub const FETCH_BATCH_SIZE_SETTING: &'static str = "warp.fetcher.fetchBatchSize";
pub const LOAD_BUNDLED_FILES_DEFAULT: bool = true;
pub const LOAD_BUNDLED_FILES_SETTING: &'static str = "warp.container.loadBundledFiles";
@@ -81,8 +81,8 @@ impl PluginSettings {
let fetch_size_props = json!({
"title" : "Fetch Batch Limit",
"type" : "number",
- "minValue" : 1,
- "maxValue" : 1000,
+ "minValue" : 100,
+ "maxValue" : 20000,
"default" : Self::FETCH_BATCH_SIZE_DEFAULT,
"description" : "The maximum number of functions to fetch in a single batch. This is used to limit the amount of functions to fetch at once, lowering this value will make the fetch process more comprehensive at the cost of more network requests.",
"ignore" : [],
diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs
index 1f4ef101..52c8e249 100644
--- a/plugins/warp/src/plugin/workflow.rs
+++ b/plugins/warp/src/plugin/workflow.rs
@@ -24,6 +24,7 @@ use std::cmp::Ordering;
use std::collections::HashMap;
use std::time::Instant;
use warp::r#type::class::function::{Location, RegisterLocation, StackLocation};
+use warp::signature::constraint::ConstraintGUID;
use warp::signature::function::{Function, FunctionGUID};
use warp::target::Target;
@@ -171,7 +172,7 @@ pub fn run_matcher(view: &BinaryView) {
.maximum_possible_functions
.is_some_and(|max| max < matched_functions.len() as u64)
{
- tracing::warn!(
+ tracing::debug!(
"Skipping {}, too many possible functions: {}",
guid,
matched_functions.len()
@@ -270,6 +271,20 @@ pub fn run_fetcher(view: &BinaryView) {
let mut query_opts = QueryOptions::new_with_view(view);
let plugin_settings = PluginSettings::from_settings(&view_settings, &mut query_opts);
+ let is_ignored_func = |f: &BNFunction| !f.function_tags(None, Some(IGNORE_TAG_NAME)).is_empty();
+
+ let constraints: Vec<ConstraintGUID> = view
+ .functions()
+ .iter()
+ // Skip functions that have the ignored tag! Otherwise, we will store their constraints.
+ .filter(|f| !is_ignored_func(f))
+ .filter_map(|f| {
+ let function = try_cached_function_match(&f)?;
+ Some(function.constraints.into_iter().map(|c| c.guid))
+ })
+ .flatten()
+ .collect();
+
let Some(function_set) = FunctionSet::from_view(view) else {
background_task.finish();
return;
@@ -285,8 +300,12 @@ pub fn run_fetcher(view: &BinaryView) {
if background_task.is_cancelled() {
break;
}
- let _ =
- container.fetch_functions(target, &plugin_settings.allowed_source_tags, batch);
+ let _ = container.fetch_functions(
+ target,
+ &plugin_settings.allowed_source_tags,
+ batch,
+ &constraints,
+ );
}
}
});