1use binaryninjacore_sys::{
36 BNBinaryView, BNFunction, BNProject, BNRegisterPluginCommand,
37 BNRegisterPluginCommandForAddress, BNRegisterPluginCommandForFunction,
38 BNRegisterPluginCommandForProject, BNRegisterPluginCommandForRange,
39};
40
41use crate::binary_view::BinaryView;
42use crate::function::Function;
43use crate::project::Project;
44use crate::string::IntoCStr;
45use std::ops::Range;
46use std::os::raw::c_void;
47use std::ptr::NonNull;
48
49pub trait Command: 'static + Sync {
51 fn action(&self, view: &BinaryView);
52 fn valid(&self, view: &BinaryView) -> bool;
53}
54
55impl<T> Command for T
56where
57 T: 'static + Sync + Fn(&BinaryView),
58{
59 fn action(&self, view: &BinaryView) {
60 self(view);
61 }
62
63 fn valid(&self, _view: &BinaryView) -> bool {
64 true
65 }
66}
67
68pub fn register_command<C: Command>(name: &str, desc: &str, command: C) {
99 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView)
100 where
101 C: Command,
102 {
103 let cmd = unsafe { &*(ctxt as *const C) };
104 debug_assert!(!view.is_null());
105 let view = BinaryView { handle: view };
106 let _span = ffi_span!("Command::action", view);
107 cmd.action(&view);
108 }
109
110 extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool
111 where
112 C: Command,
113 {
114 let cmd = unsafe { &*(ctxt as *const C) };
115 debug_assert!(!view.is_null());
116 let view = BinaryView { handle: view };
117 let _span = ffi_span!("Command::valid", view);
118 cmd.valid(&view)
119 }
120
121 let name = name.to_cstr();
122 let desc = desc.to_cstr();
123 let ctxt = Box::into_raw(Box::new(command));
124 unsafe {
125 BNRegisterPluginCommand(
126 name.as_ptr(),
127 desc.as_ptr(),
128 Some(cb_action::<C>),
129 Some(cb_valid::<C>),
130 ctxt as *mut _,
131 );
132 }
133}
134
135pub trait AddressCommand: 'static + Sync {
137 fn action(&self, view: &BinaryView, addr: u64);
138 fn valid(&self, view: &BinaryView, addr: u64) -> bool;
139}
140
141impl<T> AddressCommand for T
142where
143 T: 'static + Sync + Fn(&BinaryView, u64),
144{
145 fn action(&self, view: &BinaryView, addr: u64) {
146 self(view, addr);
147 }
148
149 fn valid(&self, _view: &BinaryView, _addr: u64) -> bool {
150 true
151 }
152}
153
154pub fn register_command_for_address<C: AddressCommand>(name: &str, desc: &str, command: C) {
185 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64)
186 where
187 C: AddressCommand,
188 {
189 let cmd = unsafe { &*(ctxt as *const C) };
190 debug_assert!(!view.is_null());
191 let view = BinaryView { handle: view };
192 let _span = ffi_span!("AddressCommand::action", view);
193 cmd.action(&view, addr);
194 }
195
196 extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) -> bool
197 where
198 C: AddressCommand,
199 {
200 let cmd = unsafe { &*(ctxt as *const C) };
201 debug_assert!(!view.is_null());
202 let view = BinaryView { handle: view };
203 let _span = ffi_span!("AddressCommand::valid", view);
204 cmd.valid(&view, addr)
205 }
206
207 let name = name.to_cstr();
208 let desc = desc.to_cstr();
209 let ctxt = Box::into_raw(Box::new(command));
210 unsafe {
211 BNRegisterPluginCommandForAddress(
212 name.as_ptr(),
213 desc.as_ptr(),
214 Some(cb_action::<C>),
215 Some(cb_valid::<C>),
216 ctxt as *mut _,
217 );
218 }
219}
220
221pub trait RangeCommand: 'static + Sync {
223 fn action(&self, view: &BinaryView, range: Range<u64>);
224 fn valid(&self, view: &BinaryView, range: Range<u64>) -> bool;
225}
226
227impl<T> RangeCommand for T
228where
229 T: 'static + Sync + Fn(&BinaryView, Range<u64>),
230{
231 fn action(&self, view: &BinaryView, range: Range<u64>) {
232 self(view, range);
233 }
234
235 fn valid(&self, _view: &BinaryView, _range: Range<u64>) -> bool {
236 true
237 }
238}
239
240pub fn register_command_for_range<C>(name: &str, desc: &str, command: C)
272where
273 C: RangeCommand,
274{
275 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64)
276 where
277 C: RangeCommand,
278 {
279 let cmd = unsafe { &*(ctxt as *const C) };
280 debug_assert!(!view.is_null());
281 let view = BinaryView { handle: view };
282 let _span = ffi_span!("RangeCommand::action", view);
283 cmd.action(&view, addr..addr.wrapping_add(len));
284 }
285
286 extern "C" fn cb_valid<C>(
287 ctxt: *mut c_void,
288 view: *mut BNBinaryView,
289 addr: u64,
290 len: u64,
291 ) -> bool
292 where
293 C: RangeCommand,
294 {
295 let cmd = unsafe { &*(ctxt as *const C) };
296 debug_assert!(!view.is_null());
297 let view = BinaryView { handle: view };
298 let _span = ffi_span!("RangeCommand::valid", view);
299 cmd.valid(&view, addr..addr.wrapping_add(len))
300 }
301
302 let name = name.to_cstr();
303 let desc = desc.to_cstr();
304 let ctxt = Box::into_raw(Box::new(command));
305 unsafe {
306 BNRegisterPluginCommandForRange(
307 name.as_ptr(),
308 desc.as_ptr(),
309 Some(cb_action::<C>),
310 Some(cb_valid::<C>),
311 ctxt as *mut _,
312 );
313 }
314}
315
316pub trait FunctionCommand: 'static + Sync {
318 fn action(&self, view: &BinaryView, func: &Function);
319 fn valid(&self, view: &BinaryView, func: &Function) -> bool;
320}
321
322impl<T> FunctionCommand for T
323where
324 T: 'static + Sync + Fn(&BinaryView, &Function),
325{
326 fn action(&self, view: &BinaryView, func: &Function) {
327 self(view, func);
328 }
329
330 fn valid(&self, _view: &BinaryView, _func: &Function) -> bool {
331 true
332 }
333}
334
335pub fn register_command_for_function<C: FunctionCommand>(name: &str, desc: &str, command: C) {
367 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction)
368 where
369 C: FunctionCommand,
370 {
371 let cmd = unsafe { &*(ctxt as *const C) };
372 debug_assert!(!view.is_null());
373 let view = BinaryView { handle: view };
374 debug_assert!(!func.is_null());
375 let func = Function { handle: func };
376 let _span = ffi_span!("FunctionCommand::action", view);
377 cmd.action(&view, &func);
378 }
379
380 extern "C" fn cb_valid<C>(
381 ctxt: *mut c_void,
382 view: *mut BNBinaryView,
383 func: *mut BNFunction,
384 ) -> bool
385 where
386 C: FunctionCommand,
387 {
388 let cmd = unsafe { &*(ctxt as *const C) };
389 debug_assert!(!view.is_null());
390 let view = BinaryView { handle: view };
391 debug_assert!(!func.is_null());
392 let func = Function { handle: func };
393 let _span = ffi_span!("FunctionCommand::valid", view);
394 cmd.valid(&view, &func)
395 }
396
397 let name = name.to_cstr();
398 let desc = desc.to_cstr();
399 let ctxt = Box::into_raw(Box::new(command));
400 unsafe {
401 BNRegisterPluginCommandForFunction(
402 name.as_ptr(),
403 desc.as_ptr(),
404 Some(cb_action::<C>),
405 Some(cb_valid::<C>),
406 ctxt as *mut _,
407 );
408 }
409}
410
411pub trait ProjectCommand: 'static + Sync {
412 fn action(&self, project: &Project);
413 fn valid(&self, project: &Project) -> bool;
414}
415
416pub fn register_command_for_project<C: ProjectCommand>(name: &str, desc: &str, command: C) {
417 extern "C" fn cb_action<C>(ctxt: *mut c_void, project: *mut BNProject)
418 where
419 C: ProjectCommand,
420 {
421 let cmd = unsafe { &*(ctxt as *const C) };
422 let handle = NonNull::new(project).expect("project handle is null");
423 let project = Project { handle };
424 cmd.action(&project);
425 }
426
427 extern "C" fn cb_valid<C>(ctxt: *mut c_void, project: *mut BNProject) -> bool
428 where
429 C: ProjectCommand,
430 {
431 let cmd = unsafe { &*(ctxt as *const C) };
432 let handle = NonNull::new(project).expect("project handle is null");
433 let project = Project { handle };
434 cmd.valid(&project)
435 }
436
437 let name = name.to_cstr();
438 let desc = desc.to_cstr();
439 let ctxt = Box::into_raw(Box::new(command));
440 unsafe {
441 BNRegisterPluginCommandForProject(
442 name.as_ptr(),
443 desc.as_ptr(),
444 Some(cb_action::<C>),
445 Some(cb_valid::<C>),
446 ctxt as *mut _,
447 );
448 }
449}