Skip to content

Commit 35c681c

Browse files
committed
warp wip
This is a partial commit that builds, this is so that mason can go do something else.
1 parent a302d1b commit 35c681c

37 files changed

+1349
-1635
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/warp/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dashmap = "6.1"
1717
walkdir = "2.5"
1818
rfd = "0.15"
1919
serde_json = "1.0"
20+
uuid = { version = "1.12.0", features = ["v4"] }
2021

2122
# For sigem
2223
env_logger = { version = "0.11", optional = true }

plugins/warp/benches/convert.rs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,36 @@ use criterion::{criterion_group, criterion_main, Criterion};
44
use std::path::PathBuf;
55
use warp_ninja::convert::from_bn_type;
66

7+
// These are the target files present in OUT_DIR
8+
// Add the files to fixtures/bin
9+
static TARGET_FILES: [&str; 1] = ["atox.obj"];
10+
711
pub fn type_conversion_benchmark(c: &mut Criterion) {
812
let session = Session::new().expect("Failed to initialize session");
913
let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap();
10-
for entry in std::fs::read_dir(out_dir).expect("Failed to read OUT_DIR") {
11-
let entry = entry.expect("Failed to read directory entry");
12-
let path = entry.path();
13-
if path.is_file() {
14-
if let Some(bv) = session.load(path.to_str().unwrap()) {
15-
let functions = bv.functions();
16-
c.bench_function("type conversion all functions", |b| {
17-
b.iter(|| {
18-
for func in &functions {
19-
from_bn_type(&bv, &func.function_type(), u8::MAX);
20-
}
21-
})
22-
});
14+
for file_name in TARGET_FILES {
15+
let path = out_dir.join(file_name);
16+
let view = session.load(&path).expect("Failed to load view");
17+
18+
// Bench function types.
19+
let functions: Vec<_> = view.functions().iter().map(|f| f.to_owned()).collect();
20+
c.bench_function("type conversion all functions", |b| {
21+
b.iter(|| {
22+
for func in &functions {
23+
from_bn_type(&view, &func.function_type(), u8::MAX);
24+
}
25+
})
26+
});
2327

24-
let types = bv.types();
25-
c.bench_function("type conversion all types", |b| {
26-
b.iter(|| {
27-
for ty in &types {
28-
from_bn_type(&bv, &ty.ty, u8::MAX);
29-
}
30-
})
31-
});
32-
}
33-
}
28+
// Bench view types.
29+
let types = view.types().to_vec();
30+
c.bench_function("type conversion all types", |b| {
31+
b.iter(|| {
32+
for ty in &types {
33+
from_bn_type(&view, &ty.ty, u8::MAX);
34+
}
35+
})
36+
});
3437
}
3538
}
3639

plugins/warp/benches/function.rs

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,45 @@ use binaryninja::binary_view::BinaryViewExt;
22
use binaryninja::headless::Session;
33
use criterion::{criterion_group, criterion_main, Criterion};
44
use rayon::prelude::*;
5+
use std::path::PathBuf;
56
use warp_ninja::build_function;
67
use warp_ninja::cache::FunctionCache;
78

9+
// These are the target files present in OUT_DIR
10+
// Add the files to fixtures/bin
11+
static TARGET_FILES: [&str; 1] = ["atox.obj"];
12+
813
pub fn function_benchmark(c: &mut Criterion) {
914
let session = Session::new().expect("Failed to initialize session");
10-
let bv = session.load(env!("TEST_BIN_LIBRARY_OBJ")).unwrap();
11-
let functions = bv.functions();
12-
assert_eq!(functions.len(), 6);
13-
let mut function_iter = functions.into_iter();
14-
let first_function = function_iter.next().unwrap();
15-
16-
c.bench_function("signature first function", |b| {
17-
b.iter(|| {
18-
let _ = build_function(&first_function, &first_function.low_level_il().unwrap());
19-
})
20-
});
15+
let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap();
16+
for file_name in TARGET_FILES {
17+
let path = out_dir.join(file_name);
18+
let view = session.load(&path).expect("Failed to load view");
2119

22-
c.bench_function("signature all functions", |b| {
23-
b.iter(|| {
24-
for func in &functions {
25-
let _ = build_function(&func, &func.low_level_il().unwrap());
26-
}
27-
})
28-
});
20+
let functions: Vec<_> = view.functions().iter().map(|f| f.to_owned()).collect();
21+
// Bench all functions sequentially
22+
c.bench_function("signature all functions", |b| {
23+
b.iter(|| {
24+
for func in &functions {
25+
let _ = build_function(&func, &func.low_level_il().unwrap());
26+
}
27+
})
28+
});
2929

30-
let cache = FunctionCache::default();
31-
c.bench_function("signature all functions rayon", |b| {
32-
b.iter(|| {
33-
functions
34-
.par_iter()
35-
.map_with(cache.clone(), |par_cache, func| {
36-
let llil = func.low_level_il().ok()?;
37-
Some(par_cache.function(func.as_ref(), llil.as_ref()))
38-
})
39-
.collect::<Vec<_>>()
40-
})
41-
});
30+
// Bench all functions in parallel
31+
let cache = FunctionCache::default();
32+
c.bench_function("signature all functions rayon", |b| {
33+
b.iter(|| {
34+
functions
35+
.par_iter()
36+
.map_with(cache.clone(), |par_cache, func| {
37+
let llil = func.low_level_il().ok()?;
38+
Some(par_cache.function(func.as_ref(), llil.as_ref()))
39+
})
40+
.collect::<Vec<_>>()
41+
})
42+
});
43+
}
4244
}
4345

4446
criterion_group!(benches, function_benchmark);

plugins/warp/benches/guid.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
11
use binaryninja::binary_view::BinaryViewExt;
22
use binaryninja::headless::Session;
33
use criterion::{criterion_group, criterion_main, Criterion};
4+
use std::path::PathBuf;
45
use warp_ninja::function_guid;
56

7+
// These are the target files present in OUT_DIR
8+
// Add the files to fixtures/bin
9+
static TARGET_FILES: [&str; 1] = ["atox.obj"];
10+
611
pub fn guid_benchmark(c: &mut Criterion) {
712
let session = Session::new().expect("Failed to initialize session");
8-
let bv = session.load(env!("TEST_BIN_LIBRARY_OBJ")).unwrap();
9-
let functions = bv.functions();
10-
assert_eq!(functions.len(), 6);
11-
let mut function_iter = functions.into_iter();
12-
let first_function = function_iter.next().unwrap();
13+
let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap();
14+
for file_name in TARGET_FILES {
15+
let path = out_dir.join(file_name);
16+
let view = session.load(&path).expect("Failed to load view");
1317

14-
c.bench_function("function guid", |b| {
15-
b.iter(|| {
16-
let llil = first_function.low_level_il().unwrap();
17-
function_guid(&first_function, &llil);
18-
})
19-
});
18+
let functions: Vec<_> = view.functions().iter().map(|f| f.to_owned()).collect();
19+
// Bench all functions sequentially
20+
c.bench_function("guid all functions", |b| {
21+
b.iter(|| {
22+
for func in &functions {
23+
let llil = func.low_level_il().unwrap();
24+
function_guid(&func, &llil);
25+
}
26+
})
27+
});
28+
}
2029
}
2130

2231
criterion_group!(benches, guid_benchmark);
14.1 KB
Binary file not shown.

plugins/warp/src/cache.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod container;
12
pub mod function;
23
pub mod guid;
34
pub mod type_reference;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::cache::ViewID;
2+
use crate::container::Container;
3+
use binaryninja::binary_view::BinaryView;
4+
use dashmap::DashMap;
5+
use std::sync::OnceLock;
6+
7+
pub static CONTAINER_CACHE: OnceLock<DashMap<ViewID, ContainerCache>> = OnceLock::new();
8+
9+
pub fn cached_containers(view: &BinaryView, f: impl Fn(&dyn Container)) {
10+
let view_id = ViewID::from(view.as_ref());
11+
let containers_cache = CONTAINER_CACHE.get_or_init(Default::default);
12+
if let Some(cache) = containers_cache.get(&view_id) {
13+
for container in cache.containers() {
14+
f(container);
15+
}
16+
}
17+
}
18+
19+
// TODO: The static lifetime here is a little wierd... (we need it to Box)
20+
pub fn add_cached_container(view: &BinaryView, container: impl Container + 'static) {
21+
let view_id = ViewID::from(view.as_ref());
22+
let containers_cache = CONTAINER_CACHE.get_or_init(Default::default);
23+
let mut cache = containers_cache
24+
.entry(view_id)
25+
.or_insert_with(Default::default);
26+
// TODO: What happens if we have already added the container?
27+
// TODO: We need to replace container.
28+
cache.add_container(Box::new(container));
29+
}
30+
31+
#[derive(Default)]
32+
pub struct ContainerCache {
33+
pub cache: Vec<Box<dyn Container>>,
34+
}
35+
36+
impl ContainerCache {
37+
pub fn add_container(&mut self, container: Box<dyn Container>) {
38+
self.cache.push(container);
39+
}
40+
41+
pub fn containers(&self) -> impl Iterator<Item = &dyn Container> {
42+
self.cache.iter().map(|c| c.as_ref())
43+
}
44+
}

plugins/warp/src/cache/function.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ pub fn clear_function_cache(view: &BinaryView) {
2929
}
3030
}
3131

32-
// TODO: The cached function match here might need to remove the function callback.
3332
pub fn cached_function_match<F>(function: &BNFunction, f: F) -> Option<Function>
3433
where
3534
F: Fn() -> Option<Function>,

plugins/warp/src/container.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::collections::HashMap;
2+
use std::fmt::{Debug, Display};
3+
use std::hash::Hash;
4+
use uuid::Uuid;
5+
use warp::r#type::guid::TypeGUID;
6+
use warp::r#type::Type;
7+
use warp::signature::function::{Function, FunctionGUID};
8+
9+
pub mod disk;
10+
pub mod memory;
11+
pub mod network;
12+
13+
/// Represents the ID for a single container source.
14+
///
15+
/// A source is used to relate types and functions separate from the container. This allows
16+
/// type name lookups and for containers which are bandwidth sensitive to exist.
17+
///
18+
/// An example of a bandwidth sensitive container would be a container which pulls functions over
19+
/// the network instead of from memory or disk.
20+
#[derive(Clone, Debug, Eq, PartialEq, Hash, Copy)]
21+
pub struct SourceId(Uuid);
22+
23+
impl SourceId {
24+
pub fn new() -> Self {
25+
Self(Uuid::new_v4())
26+
}
27+
}
28+
29+
/// Storage for WARP functions.
30+
///
31+
/// Containers are made up of sources, see [`SourceId`] for more details.
32+
pub trait Container: Send + Sync + Display + Debug {
33+
/// Get the sources that contain a type with the given [`TypeGUID`].
34+
fn sources_with_type_guid(&self, guid: &TypeGUID) -> Vec<&SourceId>;
35+
36+
/// Plural version of [`Container::sources_with_type_guid`].
37+
///
38+
/// Each source will have a list of the containing GUID's so that when looking up a source you give
39+
/// it only the GUID's that it knows about, for networking this means cutting down traffic significantly.
40+
fn sources_with_type_guids<'a>(
41+
&'a self,
42+
guids: &'a [TypeGUID],
43+
) -> HashMap<&'a TypeGUID, Vec<&'a SourceId>>;
44+
45+
/// Retrieve all [`TypeGUID`]'s with the given name.
46+
fn type_guids_with_name(&self, source: &SourceId, name: &str) -> Vec<TypeGUID>;
47+
48+
fn type_with_guid(&self, source: &SourceId, guid: &TypeGUID) -> Option<Type>;
49+
50+
fn has_type_with_guid(&self, source: &SourceId, guid: &TypeGUID) -> bool {
51+
self.type_with_guid(source, guid).is_some()
52+
}
53+
54+
/// Get the sources that contain functions with the given [`FunctionGUID`].
55+
fn sources_with_function_guid(&self, guid: &FunctionGUID) -> Vec<&SourceId>;
56+
57+
// TODO: Allocating with Vec is not good.
58+
/// Plural version of [`Container::sources_with_function_guid`].
59+
///
60+
/// Each source will have a list of the containing GUID's so that when looking up a source you give
61+
/// it only the GUID's that it knows about, for networking this means cutting down traffic significantly.
62+
fn sources_with_function_guids<'a>(
63+
&'a self,
64+
guids: &'a [FunctionGUID],
65+
) -> HashMap<&'a FunctionGUID, Vec<&'a SourceId>>;
66+
67+
fn functions_with_guid(&self, source: &SourceId, guid: &FunctionGUID) -> Vec<Function>;
68+
69+
fn has_function_with_guid(&self, source: &SourceId, guid: &FunctionGUID) -> bool {
70+
!self.functions_with_guid(source, guid).is_empty()
71+
}
72+
}

0 commit comments

Comments
 (0)