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 ffi_wrap!("Command::action", unsafe {
104 let cmd = &*(ctxt as *const C);
105
106 debug_assert!(!view.is_null());
107 let view = BinaryView { handle: view };
108
109 cmd.action(&view);
110 })
111 }
112
113 extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool
114 where
115 C: Command,
116 {
117 ffi_wrap!("Command::valid", unsafe {
118 let cmd = &*(ctxt as *const C);
119
120 debug_assert!(!view.is_null());
121 let view = BinaryView { handle: view };
122
123 cmd.valid(&view)
124 })
125 }
126
127 let name = name.to_cstr();
128 let desc = desc.to_cstr();
129
130 let name_ptr = name.as_ptr();
131 let desc_ptr = desc.as_ptr();
132
133 let ctxt = Box::into_raw(Box::new(command));
134
135 unsafe {
136 BNRegisterPluginCommand(
137 name_ptr,
138 desc_ptr,
139 Some(cb_action::<C>),
140 Some(cb_valid::<C>),
141 ctxt as *mut _,
142 );
143 }
144}
145
146pub trait AddressCommand: 'static + Sync {
148 fn action(&self, view: &BinaryView, addr: u64);
149 fn valid(&self, view: &BinaryView, addr: u64) -> bool;
150}
151
152impl<T> AddressCommand for T
153where
154 T: 'static + Sync + Fn(&BinaryView, u64),
155{
156 fn action(&self, view: &BinaryView, addr: u64) {
157 self(view, addr);
158 }
159
160 fn valid(&self, _view: &BinaryView, _addr: u64) -> bool {
161 true
162 }
163}
164
165pub fn register_command_for_address<C: AddressCommand>(name: &str, desc: &str, command: C) {
196 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64)
197 where
198 C: AddressCommand,
199 {
200 ffi_wrap!("AddressCommand::action", unsafe {
201 let cmd = &*(ctxt as *const C);
202
203 debug_assert!(!view.is_null());
204 let view = BinaryView { handle: view };
205
206 cmd.action(&view, addr);
207 })
208 }
209
210 extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) -> bool
211 where
212 C: AddressCommand,
213 {
214 ffi_wrap!("AddressCommand::valid", unsafe {
215 let cmd = &*(ctxt as *const C);
216
217 debug_assert!(!view.is_null());
218 let view = BinaryView { handle: view };
219
220 cmd.valid(&view, addr)
221 })
222 }
223
224 let name = name.to_cstr();
225 let desc = desc.to_cstr();
226
227 let name_ptr = name.as_ptr();
228 let desc_ptr = desc.as_ptr();
229
230 let ctxt = Box::into_raw(Box::new(command));
231
232 unsafe {
233 BNRegisterPluginCommandForAddress(
234 name_ptr,
235 desc_ptr,
236 Some(cb_action::<C>),
237 Some(cb_valid::<C>),
238 ctxt as *mut _,
239 );
240 }
241}
242
243pub trait RangeCommand: 'static + Sync {
245 fn action(&self, view: &BinaryView, range: Range<u64>);
246 fn valid(&self, view: &BinaryView, range: Range<u64>) -> bool;
247}
248
249impl<T> RangeCommand for T
250where
251 T: 'static + Sync + Fn(&BinaryView, Range<u64>),
252{
253 fn action(&self, view: &BinaryView, range: Range<u64>) {
254 self(view, range);
255 }
256
257 fn valid(&self, _view: &BinaryView, _range: Range<u64>) -> bool {
258 true
259 }
260}
261
262pub fn register_command_for_range<C>(name: &str, desc: &str, command: C)
294where
295 C: RangeCommand,
296{
297 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64)
298 where
299 C: RangeCommand,
300 {
301 ffi_wrap!("RangeCommand::action", unsafe {
302 let cmd = &*(ctxt as *const C);
303
304 debug_assert!(!view.is_null());
305 let view = BinaryView { handle: view };
306
307 cmd.action(&view, addr..addr.wrapping_add(len));
308 })
309 }
310
311 extern "C" fn cb_valid<C>(
312 ctxt: *mut c_void,
313 view: *mut BNBinaryView,
314 addr: u64,
315 len: u64,
316 ) -> bool
317 where
318 C: RangeCommand,
319 {
320 ffi_wrap!("RangeCommand::valid", unsafe {
321 let cmd = &*(ctxt as *const C);
322
323 debug_assert!(!view.is_null());
324 let view = BinaryView { handle: view };
325
326 cmd.valid(&view, addr..addr.wrapping_add(len))
327 })
328 }
329
330 let name = name.to_cstr();
331 let desc = desc.to_cstr();
332
333 let name_ptr = name.as_ptr();
334 let desc_ptr = desc.as_ptr();
335
336 let ctxt = Box::into_raw(Box::new(command));
337
338 unsafe {
339 BNRegisterPluginCommandForRange(
340 name_ptr,
341 desc_ptr,
342 Some(cb_action::<C>),
343 Some(cb_valid::<C>),
344 ctxt as *mut _,
345 );
346 }
347}
348
349pub trait FunctionCommand: 'static + Sync {
351 fn action(&self, view: &BinaryView, func: &Function);
352 fn valid(&self, view: &BinaryView, func: &Function) -> bool;
353}
354
355impl<T> FunctionCommand for T
356where
357 T: 'static + Sync + Fn(&BinaryView, &Function),
358{
359 fn action(&self, view: &BinaryView, func: &Function) {
360 self(view, func);
361 }
362
363 fn valid(&self, _view: &BinaryView, _func: &Function) -> bool {
364 true
365 }
366}
367
368pub fn register_command_for_function<C: FunctionCommand>(name: &str, desc: &str, command: C) {
400 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction)
401 where
402 C: FunctionCommand,
403 {
404 ffi_wrap!("FunctionCommand::action", unsafe {
405 let cmd = &*(ctxt as *const C);
406
407 debug_assert!(!view.is_null());
408 let view = BinaryView { handle: view };
409
410 debug_assert!(!func.is_null());
411 let func = Function { handle: func };
412
413 cmd.action(&view, &func);
414 })
415 }
416
417 extern "C" fn cb_valid<C>(
418 ctxt: *mut c_void,
419 view: *mut BNBinaryView,
420 func: *mut BNFunction,
421 ) -> bool
422 where
423 C: FunctionCommand,
424 {
425 ffi_wrap!("FunctionCommand::valid", unsafe {
426 let cmd = &*(ctxt as *const C);
427
428 debug_assert!(!view.is_null());
429 let view = BinaryView { handle: view };
430
431 debug_assert!(!func.is_null());
432 let func = Function { handle: func };
433
434 cmd.valid(&view, &func)
435 })
436 }
437
438 let name = name.to_cstr();
439 let desc = desc.to_cstr();
440
441 let name_ptr = name.as_ptr();
442 let desc_ptr = desc.as_ptr();
443
444 let ctxt = Box::into_raw(Box::new(command));
445
446 unsafe {
447 BNRegisterPluginCommandForFunction(
448 name_ptr,
449 desc_ptr,
450 Some(cb_action::<C>),
451 Some(cb_valid::<C>),
452 ctxt as *mut _,
453 );
454 }
455}
456
457pub trait ProjectCommand: 'static + Sync {
458 fn action(&self, project: &Project);
459 fn valid(&self, project: &Project) -> bool;
460}
461
462pub fn register_command_for_project<C: ProjectCommand>(name: &str, desc: &str, command: C) {
463 extern "C" fn cb_action<C>(ctxt: *mut c_void, project: *mut BNProject)
464 where
465 C: ProjectCommand,
466 {
467 ffi_wrap!("Command::action", unsafe {
468 let cmd = &*(ctxt as *const C);
469
470 let handle = NonNull::new(project).expect("project handle is null");
471 let project = Project { handle };
472
473 cmd.action(&project);
474 })
475 }
476
477 extern "C" fn cb_valid<C>(ctxt: *mut c_void, project: *mut BNProject) -> bool
478 where
479 C: ProjectCommand,
480 {
481 ffi_wrap!("Command::valid", unsafe {
482 let cmd = &*(ctxt as *const C);
483
484 let handle = NonNull::new(project).expect("project handle is null");
485 let project = Project { handle };
486
487 cmd.valid(&project)
488 })
489 }
490
491 let name = name.to_cstr();
492 let desc = desc.to_cstr();
493
494 let name_ptr = name.as_ptr();
495 let desc_ptr = desc.as_ptr();
496
497 let ctxt = Box::into_raw(Box::new(command));
498
499 unsafe {
500 BNRegisterPluginCommandForProject(
501 name_ptr,
502 desc_ptr,
503 Some(cb_action::<C>),
504 Some(cb_valid::<C>),
505 ctxt as *mut _,
506 );
507 }
508}