From ba6d08199b0067adf3222559363a819f4b11c502 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 18 Jun 2025 00:14:48 -0400 Subject: Add PluginCommand for projects and hide non-contextual commands in linear/graph view --- rust/src/command.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 5 deletions(-) (limited to 'rust/src/command.rs') diff --git a/rust/src/command.rs b/rust/src/command.rs index 46f43bbd..eecdf4a8 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -33,16 +33,18 @@ //! The return value of these functions should indicate whether they successfully initialized themselves. use binaryninjacore_sys::{ - BNBinaryView, BNFunction, BNRegisterPluginCommand, BNRegisterPluginCommandForAddress, - BNRegisterPluginCommandForFunction, BNRegisterPluginCommandForRange, + BNBinaryView, BNFunction, BNProject, BNRegisterPluginCommand, + BNRegisterPluginCommandForAddress, BNRegisterPluginCommandForFunction, + BNRegisterPluginCommandForProject, BNRegisterPluginCommandForRange, }; -use std::ops::Range; -use std::os::raw::c_void; - use crate::binary_view::BinaryView; use crate::function::Function; +use crate::project::Project; use crate::string::IntoCStr; +use std::ops::Range; +use std::os::raw::c_void; +use std::ptr::NonNull; /// The trait required for generic commands. See [register_command] for example usage. pub trait Command: 'static + Sync { @@ -451,3 +453,56 @@ pub fn register_command_for_function(name: &str, desc: &str, ); } } + +pub trait ProjectCommand: 'static + Sync { + fn action(&self, project: &Project); + fn valid(&self, project: &Project) -> bool; +} + +pub fn register_command_for_project(name: &str, desc: &str, command: C) { + extern "C" fn cb_action(ctxt: *mut c_void, project: *mut BNProject) + where + C: ProjectCommand, + { + ffi_wrap!("Command::action", unsafe { + let cmd = &*(ctxt as *const C); + + let handle = NonNull::new(project).expect("project handle is null"); + let project = Project { handle }; + + cmd.action(&project); + }) + } + + extern "C" fn cb_valid(ctxt: *mut c_void, project: *mut BNProject) -> bool + where + C: ProjectCommand, + { + ffi_wrap!("Command::valid", unsafe { + let cmd = &*(ctxt as *const C); + + let handle = NonNull::new(project).expect("project handle is null"); + let project = Project { handle }; + + cmd.valid(&project) + }) + } + + let name = name.to_cstr(); + let desc = desc.to_cstr(); + + let name_ptr = name.as_ptr(); + let desc_ptr = desc.as_ptr(); + + let ctxt = Box::into_raw(Box::new(command)); + + unsafe { + BNRegisterPluginCommandForProject( + name_ptr, + desc_ptr, + Some(cb_action::), + Some(cb_valid::), + ctxt as *mut _, + ); + } +} -- cgit v1.3.1