summaryrefslogtreecommitdiff
path: root/plugins/warp/src/plugin/ffi
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2026-03-13 12:24:18 -0700
committerMason Reed <35282038+emesare@users.noreply.github.com>2026-03-24 18:46:48 -0700
commit3c88b11e5df33116580ac008e36092775df66135 (patch)
treecd64fbe149f05683ddabcccd0db7b87356f1f8cf /plugins/warp/src/plugin/ffi
parentf325aa7b6026a1daef84931baeb1f50d7da10c10 (diff)
[WARP] Improved UX and API
- Exposes WARP type objects directly - Adds processor API (for generating warp files directly) - Adds file and chunk API - Misc cleanup - Simplified the amount of commands - Replaced the "Create" commands with a purpose built processor dialog - Added a native QT viewer for WARP files - Simplified committing to a remote with a purpose built commit dialog
Diffstat (limited to 'plugins/warp/src/plugin/ffi')
-rw-r--r--plugins/warp/src/plugin/ffi/container.rs61
-rw-r--r--plugins/warp/src/plugin/ffi/file.rs137
-rw-r--r--plugins/warp/src/plugin/ffi/function.rs19
-rw-r--r--plugins/warp/src/plugin/ffi/processor.rs187
-rw-r--r--plugins/warp/src/plugin/ffi/ty.rs75
5 files changed, 422 insertions, 57 deletions
diff --git a/plugins/warp/src/plugin/ffi/container.rs b/plugins/warp/src/plugin/ffi/container.rs
index aa0c37d3..09f15d99 100644
--- a/plugins/warp/src/plugin/ffi/container.rs
+++ b/plugins/warp/src/plugin/ffi/container.rs
@@ -3,17 +3,11 @@ use crate::container::disk::DiskContainer;
use crate::container::{
ContainerSearchItem, ContainerSearchItemKind, ContainerSearchQuery, SourcePath, SourceTag,
};
-use crate::convert::{from_bn_type, to_bn_type};
use crate::plugin::ffi::{
BNWARPConstraintGUID, BNWARPContainer, BNWARPFunction, BNWARPFunctionGUID, BNWARPSource,
- BNWARPTarget, BNWARPTypeGUID,
+ BNWARPTarget, BNWARPType, BNWARPTypeGUID,
};
-use binaryninja::architecture::CoreArchitecture;
-use binaryninja::binary_view::BinaryView;
-use binaryninja::rc::Ref;
use binaryninja::string::BnString;
-use binaryninja::types::Type;
-use binaryninjacore_sys::{BNArchitecture, BNBinaryView, BNType};
use std::collections::HashMap;
use std::ffi::{c_char, CStr};
use std::mem::ManuallyDrop;
@@ -98,32 +92,25 @@ pub unsafe extern "C" fn BNWARPContainerSearchItemGetSource(
#[no_mangle]
pub unsafe extern "C" fn BNWARPContainerSearchItemGetType(
- arch: *mut BNArchitecture,
item: *mut BNWARPContainerSearchItem,
-) -> *mut BNType {
- // NOTE: to convert the type, we must have an architecture.
- let arch = match !arch.is_null() {
- true => Some(CoreArchitecture::from_raw(arch)),
- false => None,
- };
-
+) -> *mut BNWARPType {
let item = ManuallyDrop::new(Arc::from_raw(item));
match &item.kind {
ContainerSearchItemKind::Source { .. } => std::ptr::null_mut(),
ContainerSearchItemKind::Function(func) => {
match &func.ty {
None => std::ptr::null_mut(),
- Some(ty) => {
- let bn_ty = to_bn_type(arch, &ty);
- // NOTE: The type ref has been pre-incremented for the caller.
- unsafe { Ref::into_raw(bn_ty) }.handle
+ Some(func_ty) => {
+ let arc_func_ty = Arc::new(func_ty.clone());
+ // NOTE: Freed by BNWARPFreeTypeReference
+ Arc::into_raw(arc_func_ty) as *mut BNWARPType
}
}
}
ContainerSearchItemKind::Type(ty) => {
- let bn_ty = to_bn_type(arch, &ty);
- // NOTE: The type ref has been pre-incremented for the caller.
- unsafe { Ref::into_raw(bn_ty) }.handle
+ let arc_ty = Arc::new(ty.clone());
+ // NOTE: Freed by BNWARPFreeTypeReference
+ Arc::into_raw(arc_ty) as *mut BNWARPType
}
ContainerSearchItemKind::Symbol(_) => std::ptr::null_mut(),
}
@@ -254,7 +241,7 @@ pub unsafe extern "C" fn BNWARPContainerGetSources(
return std::ptr::null_mut();
};
- // NOTE: Leak the sources to be freed by BNWARPFreeSourceList
+ // NOTE: Leak the sources to be freed by BNWARPFreeUUIDList
let boxed_sources: Box<[_]> = container.sources().unwrap_or_default().into_boxed_slice();
*count = boxed_sources.len();
Box::into_raw(boxed_sources) as *mut BNWARPSource
@@ -389,14 +376,11 @@ pub unsafe extern "C" fn BNWARPContainerAddFunctions(
#[no_mangle]
pub unsafe extern "C" fn BNWARPContainerAddTypes(
- view: *mut BNBinaryView,
container: *mut BNWARPContainer,
source: *const BNWARPSource,
- types: *mut *mut BNType,
+ types: *mut *mut BNWARPType,
count: usize,
) -> bool {
- let view = unsafe { BinaryView::from_raw(view) };
-
let arc_container = ManuallyDrop::new(Arc::from_raw(container));
let Ok(mut container) = arc_container.write() else {
return false;
@@ -405,10 +389,11 @@ pub unsafe extern "C" fn BNWARPContainerAddTypes(
let source = unsafe { *source };
let types_ptr = std::slice::from_raw_parts(types, count);
+ // TODO: We have to clone the objects here to make the type checker happy.
+ // TODO: See about avoiding this later.
let types: Vec<_> = types_ptr
.iter()
- .map(|&t| Type::from_raw(t))
- .map(|ty| from_bn_type(&view, &ty, 255))
+ .map(|&t| unsafe { ManuallyDrop::new(Arc::from_raw(t)).as_ref().clone() })
.collect();
container.add_types(&source, &types).is_ok()
}
@@ -476,7 +461,7 @@ pub unsafe extern "C" fn BNWARPContainerGetSourcesWithFunctionGUID(
let guid = unsafe { *guid };
- // NOTE: Leak the sources to be freed by BNWARPFreeSourceList
+ // NOTE: Leak the sources to be freed by BNWARPFreeUUIDList
let boxed_sources: Box<[_]> = container
.sources_with_function_guid(&target, &guid)
.unwrap_or_default()
@@ -498,7 +483,7 @@ pub unsafe extern "C" fn BNWARPContainerGetSourcesWithTypeGUID(
let guid = unsafe { *guid };
- // NOTE: Leak the sources to be freed by BNWARPFreeSourceList
+ // NOTE: Leak the sources to be freed by BNWARPFreeUUIDList
let boxed_sources: Box<[_]> = container
.sources_with_type_guid(&guid)
.unwrap_or_default()
@@ -538,22 +523,17 @@ pub unsafe extern "C" fn BNWARPContainerGetFunctionsWithGUID(
Box::into_raw(raw_boxed_functions) as *mut *mut BNWARPFunction
}
-// TODO: Swap arch to Target?
#[no_mangle]
pub unsafe extern "C" fn BNWARPContainerGetTypeWithGUID(
- arch: *mut BNArchitecture,
container: *mut BNWARPContainer,
source: *const BNWARPSource,
guid: *const BNWARPTypeGUID,
-) -> *mut BNType {
+) -> *mut BNWARPType {
let arc_container = ManuallyDrop::new(Arc::from_raw(container));
let Ok(container) = arc_container.read() else {
return std::ptr::null_mut();
};
- // NOTE: to convert the type, we must have an architecture.
- let arch = CoreArchitecture::from_raw(arch);
-
let source = unsafe { *source };
let guid = unsafe { *guid };
@@ -561,9 +541,10 @@ pub unsafe extern "C" fn BNWARPContainerGetTypeWithGUID(
let Some(ty) = container.type_with_guid(&source, &guid).unwrap_or_default() else {
return std::ptr::null_mut();
};
- let function_type = to_bn_type(Some(arch), &ty);
- // NOTE: The type ref has been pre-incremented for the caller.
- unsafe { Ref::into_raw(function_type) }.handle
+
+ let arc_ty = Arc::new(ty);
+ // NOTE: Freed by BNWARPFreeTypeReference
+ Arc::into_raw(arc_ty) as *mut BNWARPType
}
#[no_mangle]
diff --git a/plugins/warp/src/plugin/ffi/file.rs b/plugins/warp/src/plugin/ffi/file.rs
index 951b5eb2..3abfe5aa 100644
--- a/plugins/warp/src/plugin/ffi/file.rs
+++ b/plugins/warp/src/plugin/ffi/file.rs
@@ -1,11 +1,43 @@
+use crate::plugin::ffi::{BNWARPFunction, BNWARPTarget, BNWARPType};
+use binaryninja::data_buffer::DataBuffer;
+use binaryninjacore_sys::BNDataBuffer;
use std::ffi::c_char;
+use std::mem::ManuallyDrop;
use std::sync::Arc;
-use warp::WarpFile;
+use warp::chunk::ChunkKind;
+use warp::{WarpFile, WarpFileHeader};
-pub type BNWARPFile = WarpFile<'static>;
+/// A [`WarpFile`] wrapper that uses reference counting to manage its chunks lifetime.
+///
+/// Used primarily when passing to the C FFI so that chunks do not need to have a complicated lifetime.
+pub struct RcWarpFile {
+ pub header: WarpFileHeader,
+ pub chunks: Vec<Arc<warp::chunk::Chunk<'static>>>,
+}
+
+impl From<WarpFile<'static>> for RcWarpFile {
+ fn from(file: WarpFile<'static>) -> Self {
+ let chunks = file.chunks.into_iter().map(|c| Arc::new(c)).collect();
+ Self {
+ header: file.header,
+ chunks,
+ }
+ }
+}
+
+impl From<&RcWarpFile> for WarpFile<'static> {
+ fn from(rc_file: &RcWarpFile) -> Self {
+ let chunks = rc_file.chunks.iter().map(|c| (**c).clone()).collect();
+ Self {
+ header: rc_file.header.clone(),
+ chunks,
+ }
+ }
+}
+
+pub type BNWARPFile = RcWarpFile;
-// TODO: At some point we may want to expose chunks directly. For now we will just enumerate all of them.
-// pub type BNWARPChunk = warp::chunk::Chunk<'static>;
+pub type BNWARPChunk = warp::chunk::Chunk<'static>;
// TODO: From bytes as well.
#[no_mangle]
@@ -20,7 +52,78 @@ pub unsafe extern "C" fn BNWARPNewFileFromPath(path: *mut c_char) -> *mut BNWARP
let Some(file) = WarpFile::from_owned_bytes(bytes) else {
return std::ptr::null_mut();
};
- Arc::into_raw(Arc::new(file)) as *mut BNWARPFile
+ let rc_file = RcWarpFile::from(file);
+ Arc::into_raw(Arc::new(rc_file)) as *mut BNWARPFile
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFileGetChunks(
+ file: *mut BNWARPFile,
+ count: *mut usize,
+) -> *mut *mut BNWARPChunk {
+ let arc_file = ManuallyDrop::new(Arc::from_raw(file));
+ *count = arc_file.chunks.len();
+ let boxed_chunks: Box<[_]> = arc_file
+ .chunks
+ .iter()
+ .map(|c| Arc::into_raw(c.clone()))
+ .collect();
+ Box::into_raw(boxed_chunks) as *mut *mut BNWARPChunk
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFileToDataBuffer(file: *mut BNWARPFile) -> *mut BNDataBuffer {
+ let arc_file = ManuallyDrop::new(Arc::from_raw(file));
+ let warp_file = WarpFile::from(arc_file.as_ref());
+ let buffer = DataBuffer::new(&warp_file.to_bytes());
+ buffer.into_raw()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPChunkGetTarget(chunk: *const BNWARPChunk) -> *mut BNWARPTarget {
+ let chunk = unsafe { &*chunk };
+ let chunk_target = chunk.header.target.clone();
+ Arc::into_raw(Arc::new(chunk_target)) as *mut BNWARPTarget
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPChunkGetFunctions(
+ chunk: *const BNWARPChunk,
+ count: *mut usize,
+) -> *mut *mut BNWARPFunction {
+ let chunk = unsafe { &*chunk };
+ match &chunk.kind {
+ ChunkKind::Signature(sc) => {
+ let boxed_funcs: Box<[_]> = sc
+ .functions()
+ .into_iter()
+ .map(|f| Arc::into_raw(Arc::new(f.clone())))
+ .collect();
+ *count = boxed_funcs.len();
+ Box::into_raw(boxed_funcs) as *mut *mut BNWARPFunction
+ }
+ ChunkKind::Type(_) => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPChunkGetTypes(
+ chunk: *const BNWARPChunk,
+ count: *mut usize,
+) -> *mut *mut BNWARPType {
+ let chunk = unsafe { &*chunk };
+ match &chunk.kind {
+ ChunkKind::Signature(_) => std::ptr::null_mut(),
+ ChunkKind::Type(tc) => {
+ let boxed_types: Box<[_]> = tc
+ .types()
+ .into_iter()
+ .map(|t| Arc::into_raw(Arc::new(t.ty.clone())))
+ .collect();
+ *count = boxed_types.len();
+ Box::into_raw(boxed_types) as *mut *mut BNWARPType
+ }
+ }
}
#[no_mangle]
@@ -36,3 +139,27 @@ pub unsafe extern "C" fn BNWARPFreeFileReference(file: *mut BNWARPFile) {
}
Arc::decrement_strong_count(file);
}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPNewChunkReference(chunk: *mut BNWARPChunk) -> *mut BNWARPChunk {
+ Arc::increment_strong_count(chunk);
+ chunk
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFreeChunkReference(chunk: *mut BNWARPChunk) {
+ if chunk.is_null() {
+ return;
+ }
+ Arc::decrement_strong_count(chunk);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFreeChunkList(chunks: *mut *mut BNWARPChunk, count: usize) {
+ let chunks_ptr = std::ptr::slice_from_raw_parts_mut(chunks, count);
+ let chunks = unsafe { Box::from_raw(chunks_ptr) };
+ for chunk in chunks {
+ // NOTE: The chunks themselves should also be arc.
+ BNWARPFreeChunkReference(chunk);
+ }
+}
diff --git a/plugins/warp/src/plugin/ffi/function.rs b/plugins/warp/src/plugin/ffi/function.rs
index 138c0a7b..2eff9e4a 100644
--- a/plugins/warp/src/plugin/ffi/function.rs
+++ b/plugins/warp/src/plugin/ffi/function.rs
@@ -1,11 +1,11 @@
use crate::build_function;
use crate::cache::{insert_cached_function_match, try_cached_function_match};
-use crate::convert::{to_bn_symbol_at_address, to_bn_type};
-use crate::plugin::ffi::{BNWARPConstraint, BNWARPFunction, BNWARPFunctionGUID};
+use crate::convert::to_bn_symbol_at_address;
+use crate::plugin::ffi::{BNWARPConstraint, BNWARPFunction, BNWARPFunctionGUID, BNWARPType};
use binaryninja::function::Function;
use binaryninja::rc::Ref;
use binaryninja::string::BnString;
-use binaryninjacore_sys::{BNFunction, BNSymbol, BNType};
+use binaryninjacore_sys::{BNFunction, BNSymbol};
use std::ffi::c_char;
use std::mem::ManuallyDrop;
use std::sync::Arc;
@@ -111,19 +111,14 @@ pub unsafe extern "C" fn BNWARPFunctionGetSymbolName(function: *mut BNWARPFuncti
}
#[no_mangle]
-pub unsafe extern "C" fn BNWARPFunctionGetType(
- function: *mut BNWARPFunction,
- analysis_function: *mut BNFunction,
-) -> *mut BNType {
- let analysis_function = Function::from_raw(analysis_function);
+pub unsafe extern "C" fn BNWARPFunctionGetType(function: *mut BNWARPFunction) -> *mut BNWARPType {
// We do not own function so we should not drop.
let function = ManuallyDrop::new(Arc::from_raw(function));
match &function.ty {
Some(func_ty) => {
- let arch = analysis_function.arch();
- let function_type = to_bn_type(Some(arch), func_ty);
- // NOTE: The type ref has been pre-incremented for the caller.
- unsafe { Ref::into_raw(function_type) }.handle
+ let arc_func_ty = Arc::new(func_ty.clone());
+ // NOTE: Freed by BNWARPFreeTypeReference
+ Arc::into_raw(arc_func_ty) as *mut BNWARPType
}
None => std::ptr::null_mut(),
}
diff --git a/plugins/warp/src/plugin/ffi/processor.rs b/plugins/warp/src/plugin/ffi/processor.rs
new file mode 100644
index 00000000..83b47f5a
--- /dev/null
+++ b/plugins/warp/src/plugin/ffi/processor.rs
@@ -0,0 +1,187 @@
+use crate::plugin::ffi::file::{BNWARPFile, RcWarpFile};
+use crate::processor::{
+ IncludedDataField, IncludedFunctionsField, ProcessingFileState, WarpFileProcessor,
+ WarpFileProcessorEntry,
+};
+use binaryninja::binary_view::BinaryView;
+use binaryninja::project::file::ProjectFile;
+use binaryninja::project::Project;
+use binaryninjacore_sys::{BNBinaryView, BNProject, BNProjectFile};
+use std::ffi::{c_char, CStr, CString};
+use std::mem::ManuallyDrop;
+use std::path::PathBuf;
+use std::ptr::NonNull;
+use std::sync::Arc;
+use warp::chunk::CompressionType;
+
+pub type BNWARPProcessor = WarpFileProcessor;
+
+#[repr(C)]
+pub struct BNWARPProcessorState {
+ cancelled: bool,
+ unprocessed_files_count: usize,
+ processed_files_count: usize,
+ analyzing_files: *mut *mut c_char,
+ analyzing_files_count: usize,
+ processing_files: *mut *mut c_char,
+ processing_files_count: usize,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPNewProcessor(
+ included_data: IncludedDataField,
+ included_functions: IncludedFunctionsField,
+ worker_count: usize,
+) -> *mut BNWARPProcessor {
+ let processor = WarpFileProcessor::new()
+ .with_file_data(included_data)
+ .with_included_functions(included_functions)
+ .with_compression_type(CompressionType::Zstd)
+ .with_entry_worker_count(worker_count);
+ Box::into_raw(Box::new(processor))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorAddPath(
+ processor: *mut BNWARPProcessor,
+ path: *const c_char,
+) {
+ let mut processor = ManuallyDrop::new(Box::from_raw(processor));
+ let path_cstr = unsafe { CStr::from_ptr(path) };
+ let path = PathBuf::from(path_cstr.to_str().unwrap());
+ // TODO: Not thread safe.
+ processor.add_entry(WarpFileProcessorEntry::Path(path));
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorAddProject(
+ processor: *mut BNWARPProcessor,
+ project: *mut BNProject,
+) {
+ let mut processor = ManuallyDrop::new(Box::from_raw(processor));
+ let project = Project::from_raw(NonNull::new(project).unwrap());
+ // TODO: Not thread safe.
+ processor.add_entry(WarpFileProcessorEntry::Project(project.to_owned()));
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorAddProjectFile(
+ processor: *mut BNWARPProcessor,
+ project_file: *mut BNProjectFile,
+) {
+ let mut processor = ManuallyDrop::new(Box::from_raw(processor));
+ let project_file = ProjectFile::from_raw(NonNull::new(project_file).unwrap());
+ // TODO: Not thread safe.
+ processor.add_entry(WarpFileProcessorEntry::ProjectFile(project_file.to_owned()));
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorAddBinaryView(
+ processor: *mut BNWARPProcessor,
+ view: *mut BNBinaryView,
+) {
+ let mut processor = ManuallyDrop::new(Box::from_raw(processor));
+ let view = BinaryView::from_raw(view);
+ // TODO: Not thread safe.
+ processor.add_entry(WarpFileProcessorEntry::BinaryView(view.to_owned()));
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorStart(processor: *mut BNWARPProcessor) -> *mut BNWARPFile {
+ let mut processor = ManuallyDrop::new(Box::from_raw(processor));
+ // TODO: Not thread safe.
+ match processor.process_entries() {
+ Ok(file) => {
+ let rc_file = RcWarpFile::from(file);
+ Arc::into_raw(Arc::new(rc_file)) as *mut BNWARPFile
+ }
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorIsCancelled(processor: *mut BNWARPProcessor) -> bool {
+ let processor = ManuallyDrop::new(Box::from_raw(processor));
+ processor
+ .state()
+ .cancelled
+ .load(std::sync::atomic::Ordering::Relaxed)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorCancel(processor: *mut BNWARPProcessor) {
+ let processor = ManuallyDrop::new(Box::from_raw(processor));
+ processor
+ .state()
+ .cancelled
+ .store(true, std::sync::atomic::Ordering::Relaxed)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPProcessorGetState(
+ processor: *mut BNWARPProcessor,
+) -> BNWARPProcessorState {
+ let processor = ManuallyDrop::new(Box::from_raw(processor));
+ let processor_state = processor.state();
+
+ let mut unprocessed_files_count = 0;
+ let mut processed_files_count = 0;
+ let mut analyzing_files = Vec::new();
+ let mut processing_files = Vec::new();
+
+ for file_state in &processor_state.files {
+ match file_state.value() {
+ ProcessingFileState::Unprocessed => unprocessed_files_count += 1,
+ ProcessingFileState::Analyzing => analyzing_files.push(file_state.key().clone()),
+ ProcessingFileState::Processing => processing_files.push(file_state.key().clone()),
+ ProcessingFileState::Processed => processed_files_count += 1,
+ }
+ }
+
+ let raw_analyzing_files: Box<[_]> = analyzing_files
+ .into_iter()
+ .map(|p| CString::new(p.to_str().unwrap()).unwrap().into_raw())
+ .collect();
+ let raw_analyzing_files_count = raw_analyzing_files.len();
+ let raw_analyzing_files_ptr = Box::into_raw(raw_analyzing_files);
+
+ let raw_processing_files: Box<[_]> = processing_files
+ .into_iter()
+ .map(|p| CString::new(p.to_str().unwrap()).unwrap().into_raw())
+ .collect();
+ let raw_processing_files_count = raw_processing_files.len();
+ let raw_processing_files_ptr = Box::into_raw(raw_processing_files);
+
+ BNWARPProcessorState {
+ cancelled: processor_state
+ .cancelled
+ .load(std::sync::atomic::Ordering::Relaxed),
+ unprocessed_files_count,
+ processed_files_count,
+ analyzing_files: raw_analyzing_files_ptr as *mut *mut c_char,
+ analyzing_files_count: raw_analyzing_files_count,
+ processing_files: raw_processing_files_ptr as *mut *mut c_char,
+ processing_files_count: raw_processing_files_count,
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFreeProcessor(processor: *mut BNWARPProcessor) {
+ let _ = Box::from_raw(processor);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFreeProcessorState(state: BNWARPProcessorState) {
+ let a_files_ptr =
+ std::ptr::slice_from_raw_parts_mut(state.analyzing_files, state.analyzing_files_count);
+ let a_files_boxed = unsafe { Box::from_raw(a_files_ptr) };
+ for path in a_files_boxed.iter() {
+ let _ = CString::from_raw(*path);
+ }
+ let p_files_ptr =
+ std::ptr::slice_from_raw_parts_mut(state.processing_files, state.processing_files_count);
+ let p_files_boxed = unsafe { Box::from_raw(p_files_ptr) };
+ for path in p_files_boxed.iter() {
+ let _ = CString::from_raw(*path);
+ }
+}
diff --git a/plugins/warp/src/plugin/ffi/ty.rs b/plugins/warp/src/plugin/ffi/ty.rs
new file mode 100644
index 00000000..6a16fdab
--- /dev/null
+++ b/plugins/warp/src/plugin/ffi/ty.rs
@@ -0,0 +1,75 @@
+use crate::convert::{from_bn_type, to_bn_type};
+use crate::plugin::ffi::BNWARPType;
+use binaryninja::architecture::CoreArchitecture;
+use binaryninja::binary_view::BinaryView;
+use binaryninja::file_metadata::FileMetadata;
+use binaryninja::rc::Ref as BnRef;
+use binaryninja::string::BnString;
+use binaryninja::types::Type;
+use binaryninjacore_sys::{BNArchitecture, BNType};
+use std::ffi::c_char;
+use std::mem::ManuallyDrop;
+use std::sync::Arc;
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPGetType(
+ analysis_type: *mut BNType,
+ confidence: u8,
+) -> *mut BNWARPType {
+ let analysis_type = Type::from_raw(analysis_type);
+ // TODO: This will leak a bunch of memory, but we need to remove the view requirement anyways.
+ let binary_view = BinaryView::from_data(&FileMetadata::new(), &[]);
+ let ty = from_bn_type(&binary_view, &analysis_type, confidence);
+ Arc::into_raw(Arc::new(ty)) as *mut BNWARPType
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPTypeGetName(ty: *mut BNWARPType) -> *mut c_char {
+ let ty = ManuallyDrop::new(Arc::from_raw(ty));
+ match ty.name.as_deref() {
+ Some(name) => BnString::into_raw(BnString::new(name)),
+ None => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPTypeGetConfidence(ty: *mut BNWARPType) -> u8 {
+ let ty = ManuallyDrop::new(Arc::from_raw(ty));
+ ty.confidence
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPTypeGetAnalysisType(
+ arch: *mut BNArchitecture,
+ ty: *mut BNWARPType,
+) -> *mut BNType {
+ let ty = ManuallyDrop::new(Arc::from_raw(ty));
+ let analysis_ty = match arch.is_null() {
+ true => to_bn_type::<CoreArchitecture>(None, &ty),
+ false => to_bn_type(Some(CoreArchitecture::from_raw(arch)), &ty),
+ };
+ BnRef::into_raw(analysis_ty).handle
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPNewTypeReference(ty: *mut BNWARPType) -> *mut BNWARPType {
+ Arc::increment_strong_count(ty);
+ ty
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFreeTypeReference(ty: *mut BNWARPType) {
+ if ty.is_null() {
+ return;
+ }
+ Arc::decrement_strong_count(ty);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BNWARPFreeTypeList(types: *mut *mut BNWARPType, count: usize) {
+ let types_ptr = std::ptr::slice_from_raw_parts_mut(types, count);
+ let types = unsafe { Box::from_raw(types_ptr) };
+ for ty in types {
+ unsafe { BNWARPFreeTypeReference(ty) };
+ }
+}