diff options
| author | Mason Reed <mason@vector35.com> | 2026-03-13 12:24:18 -0700 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2026-03-24 18:46:48 -0700 |
| commit | 3c88b11e5df33116580ac008e36092775df66135 (patch) | |
| tree | cd64fbe149f05683ddabcccd0db7b87356f1f8cf /plugins/warp/src/plugin/ffi/file.rs | |
| parent | f325aa7b6026a1daef84931baeb1f50d7da10c10 (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/file.rs')
| -rw-r--r-- | plugins/warp/src/plugin/ffi/file.rs | 137 |
1 files changed, 132 insertions, 5 deletions
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); + } +} |
