1use binaryninjacore_sys::*;
36
37use crate::binary_view::BinaryView;
38use crate::function::Function;
39use crate::project::Project;
40use crate::string::IntoCStr;
41use std::ops::Range;
42use std::os::raw::c_void;
43use std::ptr::NonNull;
44
45pub trait GlobalCommand: 'static + Sync {
46 fn action(&self);
47 fn valid(&self) -> bool;
48}
49
50pub fn register_global_command<C: GlobalCommand>(name: &str, desc: &str, command: C) {
51 extern "C" fn cb_action<C>(ctxt: *mut c_void)
52 where
53 C: GlobalCommand,
54 {
55 let cmd = unsafe { &*(ctxt as *const C) };
56 cmd.action();
57 }
58
59 extern "C" fn cb_valid<C>(ctxt: *mut c_void) -> bool
60 where
61 C: GlobalCommand,
62 {
63 let cmd = unsafe { &*(ctxt as *const C) };
64 cmd.valid()
65 }
66
67 let name = name.to_cstr();
68 let desc = desc.to_cstr();
69 let ctxt = Box::into_raw(Box::new(command));
70 unsafe {
71 BNRegisterPluginCommandGlobal(
72 name.as_ptr(),
73 desc.as_ptr(),
74 Some(cb_action::<C>),
75 Some(cb_valid::<C>),
76 ctxt as *mut _,
77 );
78 }
79}
80
81pub trait Command: 'static + Sync {
83 fn action(&self, view: &BinaryView);
84 fn valid(&self, view: &BinaryView) -> bool;
85}
86
87impl<T> Command for T
88where
89 T: 'static + Sync + Fn(&BinaryView),
90{
91 fn action(&self, view: &BinaryView) {
92 self(view);
93 }
94
95 fn valid(&self, _view: &BinaryView) -> bool {
96 true
97 }
98}
99
100pub fn register_command<C: Command>(name: &str, desc: &str, command: C) {
131 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView)
132 where
133 C: Command,
134 {
135 let cmd = unsafe { &*(ctxt as *const C) };
136 debug_assert!(!view.is_null());
137 let view = BinaryView { handle: view };
138 let _span = ffi_span!("Command::action", view);
139 cmd.action(&view);
140 }
141
142 extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool
143 where
144 C: Command,
145 {
146 let cmd = unsafe { &*(ctxt as *const C) };
147 debug_assert!(!view.is_null());
148 let view = BinaryView { handle: view };
149 let _span = ffi_span!("Command::valid", view);
150 cmd.valid(&view)
151 }
152
153 let name = name.to_cstr();
154 let desc = desc.to_cstr();
155 let ctxt = Box::into_raw(Box::new(command));
156 unsafe {
157 BNRegisterPluginCommand(
158 name.as_ptr(),
159 desc.as_ptr(),
160 Some(cb_action::<C>),
161 Some(cb_valid::<C>),
162 ctxt as *mut _,
163 );
164 }
165}
166
167pub trait AddressCommand: 'static + Sync {
169 fn action(&self, view: &BinaryView, addr: u64);
170 fn valid(&self, view: &BinaryView, addr: u64) -> bool;
171}
172
173impl<T> AddressCommand for T
174where
175 T: 'static + Sync + Fn(&BinaryView, u64),
176{
177 fn action(&self, view: &BinaryView, addr: u64) {
178 self(view, addr);
179 }
180
181 fn valid(&self, _view: &BinaryView, _addr: u64) -> bool {
182 true
183 }
184}
185
186pub fn register_command_for_address<C: AddressCommand>(name: &str, desc: &str, command: C) {
217 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64)
218 where
219 C: AddressCommand,
220 {
221 let cmd = unsafe { &*(ctxt as *const C) };
222 debug_assert!(!view.is_null());
223 let view = BinaryView { handle: view };
224 let _span = ffi_span!("AddressCommand::action", view);
225 cmd.action(&view, addr);
226 }
227
228 extern "C" fn cb_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) -> bool
229 where
230 C: AddressCommand,
231 {
232 let cmd = unsafe { &*(ctxt as *const C) };
233 debug_assert!(!view.is_null());
234 let view = BinaryView { handle: view };
235 let _span = ffi_span!("AddressCommand::valid", view);
236 cmd.valid(&view, addr)
237 }
238
239 let name = name.to_cstr();
240 let desc = desc.to_cstr();
241 let ctxt = Box::into_raw(Box::new(command));
242 unsafe {
243 BNRegisterPluginCommandForAddress(
244 name.as_ptr(),
245 desc.as_ptr(),
246 Some(cb_action::<C>),
247 Some(cb_valid::<C>),
248 ctxt as *mut _,
249 );
250 }
251}
252
253pub trait RangeCommand: 'static + Sync {
255 fn action(&self, view: &BinaryView, range: Range<u64>);
256 fn valid(&self, view: &BinaryView, range: Range<u64>) -> bool;
257}
258
259impl<T> RangeCommand for T
260where
261 T: 'static + Sync + Fn(&BinaryView, Range<u64>),
262{
263 fn action(&self, view: &BinaryView, range: Range<u64>) {
264 self(view, range);
265 }
266
267 fn valid(&self, _view: &BinaryView, _range: Range<u64>) -> bool {
268 true
269 }
270}
271
272pub fn register_command_for_range<C>(name: &str, desc: &str, command: C)
304where
305 C: RangeCommand,
306{
307 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64)
308 where
309 C: RangeCommand,
310 {
311 let cmd = unsafe { &*(ctxt as *const C) };
312 debug_assert!(!view.is_null());
313 let view = BinaryView { handle: view };
314 let _span = ffi_span!("RangeCommand::action", view);
315 cmd.action(&view, addr..addr.wrapping_add(len));
316 }
317
318 extern "C" fn cb_valid<C>(
319 ctxt: *mut c_void,
320 view: *mut BNBinaryView,
321 addr: u64,
322 len: u64,
323 ) -> bool
324 where
325 C: RangeCommand,
326 {
327 let cmd = unsafe { &*(ctxt as *const C) };
328 debug_assert!(!view.is_null());
329 let view = BinaryView { handle: view };
330 let _span = ffi_span!("RangeCommand::valid", view);
331 cmd.valid(&view, addr..addr.wrapping_add(len))
332 }
333
334 let name = name.to_cstr();
335 let desc = desc.to_cstr();
336 let ctxt = Box::into_raw(Box::new(command));
337 unsafe {
338 BNRegisterPluginCommandForRange(
339 name.as_ptr(),
340 desc.as_ptr(),
341 Some(cb_action::<C>),
342 Some(cb_valid::<C>),
343 ctxt as *mut _,
344 );
345 }
346}
347
348pub trait FunctionCommand: 'static + Sync {
350 fn action(&self, view: &BinaryView, func: &Function);
351 fn valid(&self, view: &BinaryView, func: &Function) -> bool;
352}
353
354impl<T> FunctionCommand for T
355where
356 T: 'static + Sync + Fn(&BinaryView, &Function),
357{
358 fn action(&self, view: &BinaryView, func: &Function) {
359 self(view, func);
360 }
361
362 fn valid(&self, _view: &BinaryView, _func: &Function) -> bool {
363 true
364 }
365}
366
367pub fn register_command_for_function<C: FunctionCommand>(name: &str, desc: &str, command: C) {
399 extern "C" fn cb_action<C>(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction)
400 where
401 C: FunctionCommand,
402 {
403 let cmd = unsafe { &*(ctxt as *const C) };
404 debug_assert!(!view.is_null());
405 let view = BinaryView { handle: view };
406 debug_assert!(!func.is_null());
407 let func = Function { handle: func };
408 let _span = ffi_span!("FunctionCommand::action", view);
409 cmd.action(&view, &func);
410 }
411
412 extern "C" fn cb_valid<C>(
413 ctxt: *mut c_void,
414 view: *mut BNBinaryView,
415 func: *mut BNFunction,
416 ) -> bool
417 where
418 C: FunctionCommand,
419 {
420 let cmd = unsafe { &*(ctxt as *const C) };
421 debug_assert!(!view.is_null());
422 let view = BinaryView { handle: view };
423 debug_assert!(!func.is_null());
424 let func = Function { handle: func };
425 let _span = ffi_span!("FunctionCommand::valid", view);
426 cmd.valid(&view, &func)
427 }
428
429 let name = name.to_cstr();
430 let desc = desc.to_cstr();
431 let ctxt = Box::into_raw(Box::new(command));
432 unsafe {
433 BNRegisterPluginCommandForFunction(
434 name.as_ptr(),
435 desc.as_ptr(),
436 Some(cb_action::<C>),
437 Some(cb_valid::<C>),
438 ctxt as *mut _,
439 );
440 }
441}
442
443pub trait ProjectCommand: 'static + Sync {
444 fn action(&self, project: &Project);
445 fn valid(&self, project: &Project) -> bool;
446}
447
448pub fn register_command_for_project<C: ProjectCommand>(name: &str, desc: &str, command: C) {
449 extern "C" fn cb_action<C>(ctxt: *mut c_void, project: *mut BNProject)
450 where
451 C: ProjectCommand,
452 {
453 let cmd = unsafe { &*(ctxt as *const C) };
454 let handle = NonNull::new(project).expect("project handle is null");
455 let project = Project { handle };
456 cmd.action(&project);
457 }
458
459 extern "C" fn cb_valid<C>(ctxt: *mut c_void, project: *mut BNProject) -> bool
460 where
461 C: ProjectCommand,
462 {
463 let cmd = unsafe { &*(ctxt as *const C) };
464 let handle = NonNull::new(project).expect("project handle is null");
465 let project = Project { handle };
466 cmd.valid(&project)
467 }
468
469 let name = name.to_cstr();
470 let desc = desc.to_cstr();
471 let ctxt = Box::into_raw(Box::new(command));
472 unsafe {
473 BNRegisterPluginCommandForProject(
474 name.as_ptr(),
475 desc.as_ptr(),
476 Some(cb_action::<C>),
477 Some(cb_valid::<C>),
478 ctxt as *mut _,
479 );
480 }
481}