1use std::ffi::{c_char, c_void, CStr};
4use std::ptr::NonNull;
5
6use binaryninjacore_sys::*;
7
8use crate::binary_view::{BinaryView, StringType};
9use crate::component::Component;
10use crate::database::undo::UndoEntry;
11use crate::external_library::{ExternalLibrary, ExternalLocation};
12use crate::function::Function;
13use crate::rc::Ref;
14use crate::section::Section;
15use crate::segment::Segment;
16use crate::symbol::Symbol;
17use crate::tags::{TagReference, TagType};
18use crate::types::{QualifiedName, Type, TypeArchive};
19use crate::variable::DataVariable;
20
21macro_rules! trait_handler {
22(
23 $(
24 $ffi_param_name:ident => $fun_name:ident(
25 $(
26 $arg_name:ident:
27 $raw_arg_type:ty:
28 $arg_type:ty =
29 $value_calculated:expr
30 ),* $(,)?
31 ) $(-> $ret_type:ty)?
32 ),* $(,)?
33) => {
34 #[derive(Default)]
38 pub struct DataNotificationTriggers {
39 $($fun_name: bool,)*
40 }
41
42 impl DataNotificationTriggers {
43 $(
44 pub fn $fun_name(mut self) -> Self {
45 self.$fun_name = true;
46 self
47 }
48 )*
49 }
50
51 pub trait CustomDataNotification: Sync + Send {
52 $(
53 #[inline]
54 #[allow(unused_variables)]
55 fn $fun_name(&mut self, $($arg_name: $arg_type),*) $(-> $ret_type)* {
56 $( <$ret_type as Default>::default() )*
57 }
58 )*
59
60 fn register<'a>(
61 self,
62 view: &BinaryView,
63 triggers: DataNotificationTriggers,
64 ) -> DataNotificationHandle<'a, Self> where Self: 'a + Sized {
65 register_data_notification(view, self, triggers)
66 }
67 }
68
69 $(
70 unsafe extern "C" fn $fun_name<H: CustomDataNotification>(
71 ctxt: *mut ::std::os::raw::c_void,
72 $($arg_name: $raw_arg_type),*
73 ) $(-> $ret_type)* {
74 let handle: &mut H = &mut *(ctxt as *mut H);
75 handle.$fun_name($($value_calculated),*)
76 }
77 )*
78
79 fn register_data_notification<'a, H: CustomDataNotification + 'a>(
80 view: &BinaryView,
81 notify: H,
82 triggers: DataNotificationTriggers,
83 ) -> DataNotificationHandle<'a, H> {
84 let leak_notify = Box::leak(Box::new(notify));
86 let handle = BNBinaryDataNotification {
87 context: leak_notify as *mut _ as *mut c_void,
88 $($ffi_param_name: triggers.$fun_name.then_some($fun_name::<H>)),*,
89 ..Default::default()
93 };
94 let mut boxed_handle = Box::new(handle);
96 unsafe { BNRegisterDataNotification(view.handle, boxed_handle.as_mut()) };
97 DataNotificationHandle {
98 bv: view.to_owned(),
99 handle: boxed_handle,
100 _life: std::marker::PhantomData,
101 }
102 }
103
104 pub struct DataNotificationClosure<'a> {
124 $(
125 $fun_name: Option<Box<
126 dyn FnMut($($arg_type),*) $(-> $ret_type)* + Sync + Send + 'a
127 >>,
128 )*
129 }
130
131 impl Default for DataNotificationClosure<'_> {
132 fn default() -> Self {
133 Self { $($fun_name: None,)* }
134 }
135 }
136
137 impl<'a> DataNotificationClosure<'a> {
138 pub fn new() -> Self {
139 Default::default()
140 }
141 $(
142 pub fn $fun_name<F: FnMut(
143 $($arg_type),*
144 ) $(-> $ret_type)* + Sync + Send + 'a>(mut self, param: F) -> Self {
145 self.$fun_name = Some(Box::new(param));
146 self
147 }
148 )*
149
150 pub fn register(
152 self,
153 view: &BinaryView,
154 ) -> DataNotificationHandle<'a, Self> {
155 let mut triggers = DataNotificationTriggers::default();
156 $(
157 if self.$fun_name.is_some() {
158 triggers = triggers.$fun_name();
159 }
160 )*
161 register_data_notification(view, self, triggers)
162 }
163 }
164
165 impl CustomDataNotification for DataNotificationClosure<'_> {
166 $(
167 fn $fun_name(&mut self, $($arg_name: $arg_type),*) $(-> $ret_type)* {
168 let Some(handle) = self.$fun_name.as_mut() else {
169 unreachable!();
170 };
171 handle($($arg_name),*)
172 }
173 )*
174 }
175};
176}
177
178trait_handler! {
179 notificationBarrier => notification_barrier(
180 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
181 ) -> u64,
182 dataWritten => data_written(
183 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
184 offset: u64: u64 = offset,
185 len: usize: usize = len,
186 ),
187 dataInserted => data_inserted(
188 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
189 offset: u64: u64 = offset,
190 len: usize: usize = len,
191 ),
192 dataRemoved => data_removed(
193 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
194 offset: u64: u64 = offset,
195 len: u64: u64 = len,
197 ),
198 functionAdded => function_added(
199 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
200 func: *mut BNFunction: &Function = &Function::from_raw(func),
201 ),
202 functionRemoved => function_removed(
203 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
204 func: *mut BNFunction: &Function = &Function::from_raw(func),
205 ),
206 functionUpdated => function_updated(
207 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
208 func: *mut BNFunction: &Function = &Function::from_raw(func),
209 ),
210 functionUpdateRequested => function_update_requested(
211 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
212 func: *mut BNFunction: &Function = &Function::from_raw(func),
213 ),
214 dataVariableAdded => data_variable_added(
215 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
216 var: *mut BNDataVariable: &DataVariable = &DataVariable::from_raw(&*var),
217 ),
218 dataVariableRemoved => data_variable_removed(
219 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
220 var: *mut BNDataVariable: &DataVariable = &DataVariable::from_raw(&*var),
221 ),
222 dataVariableUpdated => data_variable_updated(
223 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
224 var: *mut BNDataVariable: &DataVariable = &DataVariable::from_raw(&*var),
225 ),
226 dataMetadataUpdated => data_metadata_updated(
227 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
228 offset: u64: u64 = offset,
229 ),
230 tagTypeUpdated => tag_type_updated(
231 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
232 tag_type: *mut BNTagType: &TagType = &TagType{ handle: tag_type },
233 ),
234 tagAdded => tag_added(
235 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
236 tag_ref: *mut BNTagReference: &TagReference = &TagReference::from(&*tag_ref),
237 ),
238 tagRemoved => tag_removed(
239 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
240 tag_ref: *mut BNTagReference: &TagReference = &TagReference::from(&*tag_ref),
241 ),
242 tagUpdated => tag_updated(
243 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
244 tag_ref: *mut BNTagReference: &TagReference = &TagReference::from(&*tag_ref),
245 ),
246 symbolAdded => symbol_added(
247 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
248 sym: *mut BNSymbol: &Symbol = &Symbol::from_raw(sym),
249 ),
250 symbolRemoved => symbol_removed(
251 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
252 sym: *mut BNSymbol: &Symbol = &Symbol::from_raw(sym),
253 ),
254 symbolUpdated => symbol_updated(
255 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
256 sym: *mut BNSymbol: &Symbol = &Symbol::from_raw(sym),
257 ),
258 stringFound => string_found(
259 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
260 type_: BNStringType: StringType = type_,
261 offset: u64: u64 = offset,
262 len: usize: usize = len,
263 ),
264 stringRemoved => string_removed(
265 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
266 type_: BNStringType: StringType = type_,
267 offset: u64: u64 = offset,
268 len: usize: usize = len,
269 ),
270 typeDefined => type_defined(
271 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
272 name: *mut BNQualifiedName: &QualifiedName = &QualifiedName::from_raw(&*name),
273 type_: *mut BNType: &Type = &Type::from_raw(type_),
274 ),
275 typeUndefined => type_undefined(
276 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
277 name: *mut BNQualifiedName: &QualifiedName = &QualifiedName::from_raw(&*name),
278 type_: *mut BNType: &Type = &Type::from_raw(type_),
279 ),
280 typeReferenceChanged => type_reference_changed(
281 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
282 name: *mut BNQualifiedName: &QualifiedName = &QualifiedName::from_raw(&*name),
283 type_: *mut BNType: &Type = &Type::from_raw(type_),
284 ),
285 typeFieldReferenceChanged => type_field_reference_changed(
286 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
287 name: *mut BNQualifiedName: &QualifiedName = &QualifiedName::from_raw(&*name),
288 offset: u64: u64 = offset,
289 ),
290 segmentAdded => segment_added(
291 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
292 segment: *mut BNSegment: &Segment = &Segment::from_raw(segment),
293 ),
294 segmentRemoved => segment_removed(
295 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
296 segment: *mut BNSegment: &Segment = &Segment::from_raw(segment),
297 ),
298 segmentUpdated => segment_updated(
299 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
300 segment: *mut BNSegment: &Segment = &Segment::from_raw(segment),
301 ),
302 sectionAdded => section_added(
303 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
304 section: *mut BNSection: &Section = &Section::from_raw(section),
305 ),
306 sectionRemoved => section_removed(
307 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
308 section: *mut BNSection: &Section = &Section::from_raw(section),
309 ),
310 sectionUpdated => section_updated(
311 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
312 section: *mut BNSection: &Section = &Section::from_raw(section),
313 ),
314 componentNameUpdated => component_name_updated(
315 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
316 previous_name: *mut c_char: &str = CStr::from_ptr(previous_name).to_str().unwrap(),
317 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
318 ),
319 componentAdded => component_added(
320 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
321 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
322 ),
323 componentMoved => component_moved(
324 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
325 former_parent: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(former_parent).unwrap()),
326 new_parent: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(new_parent).unwrap()),
327 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
328 ),
329 componentRemoved => component_removed(
330 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
331 former_parent: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(former_parent).unwrap()),
332 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
333 ),
334 componentFunctionAdded => component_function_added(
335 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
336 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
337 function: *mut BNFunction: &Function = &Function::from_raw(function),
338 ),
339 componentFunctionRemoved => component_function_removed(
340 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
341 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
342 function: *mut BNFunction: &Function = &Function::from_raw(function),
343 ),
344 componentDataVariableAdded => component_data_variable_added(
345 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
346 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
347 var: *mut BNDataVariable: &DataVariable = &DataVariable::from_raw(&*var),
348 ),
349 componentDataVariableRemoved => component_data_variable_removed(
350 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
351 component: *mut BNComponent: &Component = &Component::from_raw(NonNull::new(component).unwrap()),
352 var: *mut BNDataVariable: &DataVariable = &DataVariable::from_raw(&*var),
353 ),
354 externalLibraryAdded => external_library_added(
355 data: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(data),
356 library: *mut BNExternalLibrary: &ExternalLibrary = &ExternalLibrary::from_raw(NonNull::new(library).unwrap()),
357 ),
358 externalLibraryUpdated => external_library_updated(
359 data: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(data),
360 library: *mut BNExternalLibrary: &ExternalLibrary = &ExternalLibrary::from_raw(NonNull::new(library).unwrap()),
361 ),
362 externalLibraryRemoved => external_library_removed(
363 data: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(data),
364 library: *mut BNExternalLibrary: &ExternalLibrary = &ExternalLibrary::from_raw(NonNull::new(library).unwrap()),
365 ),
366 externalLocationAdded => external_location_added(
367 data: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(data),
368 location: *mut BNExternalLocation: &ExternalLocation = &ExternalLocation::from_raw(NonNull::new(location).unwrap()),
369 ),
370 externalLocationUpdated => external_location_updated(
371 data: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(data),
372 location: *mut BNExternalLocation: &ExternalLocation = &ExternalLocation::from_raw(NonNull::new(location).unwrap()),
373 ),
374 externalLocationRemoved => external_location_removed(
375 data: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(data),
376 location: *mut BNExternalLocation: &ExternalLocation = &ExternalLocation::from_raw(NonNull::new(location).unwrap()),
377 ),
378 typeArchiveAttached => type_archive_attached(
379 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
380 id: *const c_char: &str = CStr::from_ptr(id).to_str().unwrap(),
381 path: *const c_char: &[u8] = CStr::from_ptr(path).to_bytes(),
382 ),
383 typeArchiveDetached => type_archive_detached(
384 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
385 id: *const c_char: &str = CStr::from_ptr(id).to_str().unwrap(),
386 path: *const c_char: &[u8] = CStr::from_ptr(path).to_bytes(),
387 ),
388 typeArchiveConnected => type_archive_connected(
389 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
390 archive: *mut BNTypeArchive: &TypeArchive = &TypeArchive::from_raw(NonNull::new(archive).unwrap()),
391 ),
392 typeArchiveDisconnected => type_archive_disconnected(
393 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
394 archive: *mut BNTypeArchive: &TypeArchive = &TypeArchive::from_raw(NonNull::new(archive).unwrap()),
395 ),
396 undoEntryAdded => undo_entry_added(
397 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
398 entry: *mut BNUndoEntry: &UndoEntry = &UndoEntry::from_raw(NonNull::new(entry).unwrap()),
399 ),
400 undoEntryTaken => undo_entry_taken(
401 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
402 entry: *mut BNUndoEntry: &UndoEntry = &UndoEntry::from_raw(NonNull::new(entry).unwrap()),
403 ),
404 redoEntryTaken => redo_entry_taken(
405 view: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(view),
406 entry: *mut BNUndoEntry: &UndoEntry = &UndoEntry::from_raw(NonNull::new(entry).unwrap()),
407 ),
408 rebased => rebased(
409 oldview: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(oldview),
410 newview: *mut BNBinaryView: &BinaryView = &BinaryView::from_raw(newview),
411 ),
412}
413
414pub struct DataNotificationHandle<'a, T: CustomDataNotification>
415where
416 T: 'a,
417{
418 bv: Ref<BinaryView>,
419 handle: Box<BNBinaryDataNotification>,
420 _life: std::marker::PhantomData<&'a T>,
421}
422
423impl<T: CustomDataNotification> DataNotificationHandle<'_, T> {
424 unsafe fn unregister_bv(&mut self) {
425 BNUnregisterDataNotification(self.bv.handle, self.handle.as_mut())
426 }
427
428 unsafe fn extract_context(&mut self) -> Box<T> {
429 Box::from_raw(self.handle.context as *mut T)
430 }
431
432 pub fn unregister(self) -> T {
433 let mut slf = core::mem::ManuallyDrop::new(self);
435 unsafe { slf.unregister_bv() };
436 unsafe { *slf.extract_context() }
437 }
438}
439
440impl<T: CustomDataNotification> Drop for DataNotificationHandle<'_, T> {
441 fn drop(&mut self) {
442 unsafe { self.unregister_bv() };
443 let _ctxt = unsafe { self.extract_context() };
445 }
446}