1use binaryninjacore_sys::*;
18
19pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus;
20
21use std::fmt::Debug;
22use std::marker::PhantomData;
23use std::mem::MaybeUninit;
24use std::os::raw::c_void;
25use std::ptr;
26use std::slice;
27
28use crate::architecture::Architecture;
29use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt, Result};
30use crate::metadata::Metadata;
31use crate::platform::Platform;
32use crate::rc::*;
33use crate::settings::Settings;
34use crate::string::*;
35use crate::Endianness;
36
37pub fn register_view_type<T, F>(name: &str, long_name: &str, constructor: F) -> &'static T
44where
45 T: CustomBinaryViewType,
46 F: FnOnce(BinaryViewType) -> T,
47{
48 extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool
49 where
50 T: CustomBinaryViewType,
51 {
52 let view_type = unsafe { &*(ctxt as *mut T) };
53 let data = unsafe { BinaryView::ref_from_raw(BNNewViewReference(data)) };
54 let _span = ffi_span!("BinaryViewTypeBase::is_valid_for", data);
55 view_type.is_valid_for(&data)
56 }
57
58 extern "C" fn cb_deprecated<T>(ctxt: *mut c_void) -> bool
59 where
60 T: CustomBinaryViewType,
61 {
62 ffi_wrap!("BinaryViewTypeBase::is_deprecated", unsafe {
63 let view_type = &*(ctxt as *mut T);
64 view_type.is_deprecated()
65 })
66 }
67
68 extern "C" fn cb_force_loadable<T>(ctxt: *mut c_void) -> bool
69 where
70 T: CustomBinaryViewType,
71 {
72 ffi_wrap!("BinaryViewTypeBase::is_force_loadable", unsafe {
73 let view_type = &*(ctxt as *mut T);
74 view_type.is_force_loadable()
75 })
76 }
77
78 extern "C" fn cb_has_no_initial_content<T>(ctxt: *mut c_void) -> bool
79 where
80 T: CustomBinaryViewType,
81 {
82 ffi_wrap!("BinaryViewTypeBase::has_no_initial_content", unsafe {
83 let view_type = &*(ctxt as *mut T);
84 view_type.has_no_initial_content()
85 })
86 }
87
88 extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
89 where
90 T: CustomBinaryViewType,
91 {
92 ffi_wrap!("BinaryViewTypeBase::create", unsafe {
93 let view_type = &*(ctxt as *mut T);
94 let data = BinaryView::ref_from_raw(BNNewViewReference(data));
95
96 let builder = CustomViewBuilder {
97 view_type,
98 actual_parent: &data,
99 };
100
101 let _span = ffi_span!("BinaryViewTypeBase::create", data);
102 match view_type.create_custom_view(&data, builder) {
103 Ok(bv) => {
104 Ref::into_raw(bv.handle).handle
108 }
109 Err(_) => ptr::null_mut(),
110 }
111 })
112 }
113
114 extern "C" fn cb_parse<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
115 where
116 T: CustomBinaryViewType,
117 {
118 ffi_wrap!("BinaryViewTypeBase::parse", unsafe {
119 let view_type = &*(ctxt as *mut T);
120 let data = BinaryView::ref_from_raw(BNNewViewReference(data));
121
122 let builder = CustomViewBuilder {
123 view_type,
124 actual_parent: &data,
125 };
126
127 let _span = ffi_span!("BinaryViewTypeBase::parse", data);
128 match view_type.parse_custom_view(&data, builder) {
129 Ok(bv) => {
130 Ref::into_raw(bv.handle).handle
134 }
135 Err(_) => ptr::null_mut(),
136 }
137 })
138 }
139
140 extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings
141 where
142 T: CustomBinaryViewType,
143 {
144 ffi_wrap!("BinaryViewTypeBase::load_settings", unsafe {
145 let view_type = &*(ctxt as *mut T);
146 let data = BinaryView::ref_from_raw(BNNewViewReference(data));
147
148 let _span = ffi_span!("BinaryViewTypeBase::load_settings", data);
149 match view_type.load_settings_for_data(&data) {
150 Some(settings) => Ref::into_raw(settings).handle,
151 None => ptr::null_mut() as *mut _,
152 }
153 })
154 }
155
156 let name = name.to_cstr();
157 let name_ptr = name.as_ptr();
158
159 let long_name = long_name.to_cstr();
160 let long_name_ptr = long_name.as_ptr();
161
162 let ctxt = Box::leak(Box::new(MaybeUninit::zeroed()));
163
164 let mut bn_obj = BNCustomBinaryViewType {
165 context: ctxt.as_mut_ptr() as *mut _,
166 create: Some(cb_create::<T>),
167 parse: Some(cb_parse::<T>),
168 isValidForData: Some(cb_valid::<T>),
169 isDeprecated: Some(cb_deprecated::<T>),
170 isForceLoadable: Some(cb_force_loadable::<T>),
171 getLoadSettingsForData: Some(cb_load_settings::<T>),
172 hasNoInitialContent: Some(cb_has_no_initial_content::<T>),
173 };
174
175 unsafe {
176 let handle = BNRegisterBinaryViewType(name_ptr, long_name_ptr, &mut bn_obj as *mut _);
177 if handle.is_null() {
178 drop(Box::from_raw(ctxt));
183 panic!("bvt registration failed");
184 }
185
186 ctxt.write(constructor(BinaryViewType { handle }));
187 ctxt.assume_init_mut()
188 }
189}
190
191pub trait BinaryViewTypeBase: AsRef<BinaryViewType> {
192 fn is_valid_for(&self, data: &BinaryView) -> bool;
197
198 fn is_deprecated(&self) -> bool {
203 false
204 }
205
206 fn is_force_loadable(&self) -> bool {
210 false
211 }
212
213 fn has_no_initial_content(&self) -> bool {
221 false
222 }
223
224 fn default_load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> {
225 let settings_handle =
226 unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().handle, data.handle) };
227
228 if settings_handle.is_null() {
229 None
230 } else {
231 unsafe { Some(Settings::ref_from_raw(settings_handle)) }
232 }
233 }
234
235 fn load_settings_for_data(&self, _data: &BinaryView) -> Option<Ref<Settings>> {
236 None
237 }
238}
239
240pub trait BinaryViewTypeExt: BinaryViewTypeBase {
241 fn name(&self) -> String {
242 unsafe { BnString::into_string(BNGetBinaryViewTypeName(self.as_ref().handle)) }
243 }
244
245 fn long_name(&self) -> String {
246 unsafe { BnString::into_string(BNGetBinaryViewTypeLongName(self.as_ref().handle)) }
247 }
248
249 fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) {
250 unsafe {
251 BNRegisterArchitectureForViewType(
252 self.as_ref().handle,
253 id,
254 endianness,
255 arch.as_ref().handle,
256 );
257 }
258 }
259
260 fn register_platform(&self, id: u32, plat: &Platform) {
261 let arch = plat.arch();
262
263 unsafe {
264 BNRegisterPlatformForViewType(self.as_ref().handle, id, arch.handle, plat.handle);
265 }
266 }
267
268 fn register_platform_recognizer<R>(&self, id: u32, endian: Endianness, recognizer: R)
287 where
288 R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync,
289 {
290 #[repr(C)]
291 struct PlatformRecognizerHandlerContext<R>
292 where
293 R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync,
294 {
295 recognizer: R,
296 }
297
298 extern "C" fn cb_recognize_low_level_il<R>(
299 ctxt: *mut c_void,
300 bv: *mut BNBinaryView,
301 metadata: *mut BNMetadata,
302 ) -> *mut BNPlatform
303 where
304 R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync,
305 {
306 let context = unsafe { &*(ctxt as *mut PlatformRecognizerHandlerContext<R>) };
307 let bv = unsafe { BinaryView::from_raw(bv).to_owned() };
308 let metadata = unsafe { Metadata::from_raw(metadata).to_owned() };
309 match (context.recognizer)(&bv, &metadata) {
310 Some(plat) => unsafe { Ref::into_raw(plat).handle },
311 None => std::ptr::null_mut(),
312 }
313 }
314
315 let recognizer = PlatformRecognizerHandlerContext { recognizer };
316 let raw = Box::into_raw(Box::new(recognizer));
318
319 unsafe {
320 BNRegisterPlatformRecognizerForViewType(
321 self.as_ref().handle,
322 id as u64,
323 endian,
324 Some(cb_recognize_low_level_il::<R>),
325 raw as *mut c_void,
326 )
327 }
328 }
329
330 fn open(&self, data: &BinaryView) -> Result<Ref<BinaryView>> {
331 let handle = unsafe { BNCreateBinaryViewOfType(self.as_ref().handle, data.handle) };
332
333 if handle.is_null() {
334 return Err(());
336 }
337
338 unsafe { Ok(BinaryView::ref_from_raw(handle)) }
339 }
340
341 fn parse(&self, data: &BinaryView) -> Result<Ref<BinaryView>> {
342 let handle = unsafe { BNParseBinaryViewOfType(self.as_ref().handle, data.handle) };
343
344 if handle.is_null() {
345 return Err(());
347 }
348
349 unsafe { Ok(BinaryView::ref_from_raw(handle)) }
350 }
351}
352
353impl<T: BinaryViewTypeBase> BinaryViewTypeExt for T {}
354
355#[derive(Copy, Clone, PartialEq, Eq, Hash)]
359pub struct BinaryViewType {
360 pub handle: *mut BNBinaryViewType,
361}
362
363impl BinaryViewType {
364 pub(crate) unsafe fn from_raw(handle: *mut BNBinaryViewType) -> Self {
365 debug_assert!(!handle.is_null());
366 Self { handle }
367 }
368
369 pub fn list_all() -> Array<BinaryViewType> {
370 unsafe {
371 let mut count: usize = 0;
372 let types = BNGetBinaryViewTypes(&mut count as *mut _);
373 Array::new(types, count, ())
374 }
375 }
376
377 pub fn valid_types_for_data(data: &BinaryView) -> Array<BinaryViewType> {
380 unsafe {
381 let mut count: usize = 0;
382 let types = BNGetBinaryViewTypesForData(data.handle, &mut count as *mut _);
383 Array::new(types, count, ())
384 }
385 }
386
387 pub fn by_name(name: &str) -> Result<Self> {
389 let bytes = name.to_cstr();
390 let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) };
391 match handle.is_null() {
392 false => Ok(unsafe { BinaryViewType::from_raw(handle) }),
393 true => Err(()),
394 }
395 }
396}
397
398impl BinaryViewTypeBase for BinaryViewType {
399 fn is_valid_for(&self, data: &BinaryView) -> bool {
400 unsafe { BNIsBinaryViewTypeValidForData(self.handle, data.handle) }
401 }
402
403 fn is_deprecated(&self) -> bool {
404 unsafe { BNIsBinaryViewTypeDeprecated(self.handle) }
405 }
406
407 fn is_force_loadable(&self) -> bool {
408 unsafe { BNIsBinaryViewTypeForceLoadable(self.handle) }
409 }
410
411 fn has_no_initial_content(&self) -> bool {
412 unsafe { BNBinaryViewTypeHasNoInitialContent(self.handle) }
413 }
414
415 fn load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> {
416 let settings_handle =
417 unsafe { BNGetBinaryViewLoadSettingsForData(self.handle, data.handle) };
418
419 if settings_handle.is_null() {
420 None
421 } else {
422 unsafe { Some(Settings::ref_from_raw(settings_handle)) }
423 }
424 }
425}
426
427impl Debug for BinaryViewType {
428 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
429 f.debug_struct("BinaryViewType")
430 .field("name", &self.name())
431 .field("long_name", &self.long_name())
432 .finish()
433 }
434}
435
436impl CoreArrayProvider for BinaryViewType {
437 type Raw = *mut BNBinaryViewType;
438 type Context = ();
439 type Wrapped<'a> = Guard<'a, BinaryViewType>;
440}
441
442unsafe impl CoreArrayProviderInner for BinaryViewType {
443 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
444 BNFreeBinaryViewTypeList(raw);
445 }
446
447 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
448 Guard::new(BinaryViewType::from_raw(*raw), &())
449 }
450}
451
452impl AsRef<BinaryViewType> for BinaryViewType {
453 fn as_ref(&self) -> &Self {
454 self
455 }
456}
457
458unsafe impl Send for BinaryViewType {}
459unsafe impl Sync for BinaryViewType {}
460
461pub trait CustomBinaryViewType: 'static + BinaryViewTypeBase + Sync {
462 fn create_custom_view<'builder>(
463 &self,
464 data: &BinaryView,
465 builder: CustomViewBuilder<'builder, Self>,
466 ) -> Result<CustomView<'builder>>;
467
468 fn parse_custom_view<'builder>(
469 &self,
470 data: &BinaryView,
471 builder: CustomViewBuilder<'builder, Self>,
472 ) -> Result<CustomView<'builder>> {
473 self.create_custom_view(data, builder)
475 }
476}
477
478pub struct CustomViewBuilder<'a, T: CustomBinaryViewType + ?Sized> {
480 view_type: &'a T,
481 actual_parent: &'a BinaryView,
482}
483
484pub unsafe trait CustomBinaryView: 'static + BinaryViewBase + Sync + Sized {
485 type Args: Send;
486
487 fn new(handle: &BinaryView, args: &Self::Args) -> Result<Self>;
488 fn init(&mut self, args: Self::Args) -> Result<()>;
489 fn on_after_snapshot_data_applied(&mut self) {}
490}
491
492#[must_use]
495pub struct CustomView<'builder> {
496 handle: Ref<BinaryView>,
501 _builder: PhantomData<&'builder ()>,
502}
503
504impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
505 pub fn create<V>(self, parent: &BinaryView, view_args: V::Args) -> Result<CustomView<'a>>
537 where
538 V: CustomBinaryView,
539 {
540 let file = self.actual_parent.file();
541 let view_type = self.view_type;
542
543 let view_name = view_type.name();
544
545 if let Some(bv) = file.view_of_type(&view_name) {
546 tracing::error!(
556 "attempt to create duplicate view of type '{}' (existing: {:?})",
557 view_name,
558 bv.handle
559 );
560
561 return Err(());
562 }
563
564 struct CustomViewContext<V>
567 where
568 V: CustomBinaryView,
569 {
570 raw_handle: *mut BNBinaryView,
571 state: CustomViewContextState<V>,
572 }
573
574 enum CustomViewContextState<V>
575 where
576 V: CustomBinaryView,
577 {
578 Uninitialized { args: V::Args },
579 Initialized { view: V },
580 None,
583 }
584
585 impl<V: CustomBinaryView> CustomViewContext<V> {
586 fn assume_init_ref(&self) -> &V {
587 let CustomViewContextState::Initialized { view } = &self.state else {
588 panic!("CustomViewContextState in invalid state");
589 };
590 view
591 }
592 }
593
594 extern "C" fn cb_init<V>(ctxt: *mut c_void) -> bool
595 where
596 V: CustomBinaryView,
597 {
598 ffi_wrap!("BinaryViewBase::init", unsafe {
599 let context = &mut *(ctxt as *mut CustomViewContext<V>);
600 let handle = BinaryView::ref_from_raw(context.raw_handle);
601
602 let mut state = CustomViewContextState::None;
604 core::mem::swap(&mut context.state, &mut state);
605 let CustomViewContextState::Uninitialized { args } = state else {
606 panic!("CustomViewContextState in invalid state");
607 };
608 match V::new(handle.as_ref(), &args) {
609 Ok(mut view) => match view.init(args) {
610 Ok(_) => {
611 context.state = CustomViewContextState::Initialized { view };
613 true
614 }
615 Err(_) => {
616 tracing::error!(
617 "CustomBinaryView::init failed; custom view returned Err"
618 );
619 false
620 }
621 },
622 Err(_) => {
623 tracing::error!("CustomBinaryView::new failed; custom view returned Err");
624 false
625 }
626 }
627 })
628 }
629
630 extern "C" fn cb_on_after_snapshot_data_applied<V>(ctxt: *mut c_void)
631 where
632 V: CustomBinaryView,
633 {
634 ffi_wrap!("BinaryViewBase::onAfterSnapshotDataApplied", unsafe {
635 let context = &mut *(ctxt as *mut CustomViewContext<V>);
636 if let CustomViewContextState::Initialized { view } = &mut context.state {
637 view.on_after_snapshot_data_applied();
638 }
639 })
640 }
641
642 extern "C" fn cb_free_object<V>(ctxt: *mut c_void)
643 where
644 V: CustomBinaryView,
645 {
646 ffi_wrap!("BinaryViewBase::freeObject", unsafe {
647 let context = ctxt as *mut CustomViewContext<V>;
648 let context = Box::from_raw(context);
649
650 if context.raw_handle.is_null() {
651 tracing::error!(
666 "BinaryViewBase::freeObject called on partially initialized object! crash imminent!"
667 );
668 } else if matches!(
669 &context.state,
670 CustomViewContextState::None | CustomViewContextState::Uninitialized { .. }
671 ) {
672 tracing::error!("BinaryViewBase::freeObject called on leaked/never initialized custom view!");
685 }
686 })
687 }
688
689 extern "C" fn cb_read<V>(
690 ctxt: *mut c_void,
691 dest: *mut c_void,
692 offset: u64,
693 len: usize,
694 ) -> usize
695 where
696 V: CustomBinaryView,
697 {
698 ffi_wrap!("BinaryViewBase::read", unsafe {
699 let context = &*(ctxt as *mut CustomViewContext<V>);
700 let dest = slice::from_raw_parts_mut(dest as *mut u8, len);
701 context.assume_init_ref().read(dest, offset)
702 })
703 }
704
705 extern "C" fn cb_write<V>(
706 ctxt: *mut c_void,
707 offset: u64,
708 src: *const c_void,
709 len: usize,
710 ) -> usize
711 where
712 V: CustomBinaryView,
713 {
714 ffi_wrap!("BinaryViewBase::write", unsafe {
715 let context = &*(ctxt as *mut CustomViewContext<V>);
716 let src = slice::from_raw_parts(src as *const u8, len);
717 context.assume_init_ref().write(offset, src)
718 })
719 }
720
721 extern "C" fn cb_insert<V>(
722 ctxt: *mut c_void,
723 offset: u64,
724 src: *const c_void,
725 len: usize,
726 ) -> usize
727 where
728 V: CustomBinaryView,
729 {
730 ffi_wrap!("BinaryViewBase::insert", unsafe {
731 let context = &*(ctxt as *mut CustomViewContext<V>);
732 let src = slice::from_raw_parts(src as *const u8, len);
733 context.assume_init_ref().insert(offset, src)
734 })
735 }
736
737 extern "C" fn cb_remove<V>(ctxt: *mut c_void, offset: u64, len: u64) -> usize
738 where
739 V: CustomBinaryView,
740 {
741 ffi_wrap!("BinaryViewBase::remove", unsafe {
742 let context = &*(ctxt as *mut CustomViewContext<V>);
743 context.assume_init_ref().remove(offset, len as usize)
744 })
745 }
746
747 extern "C" fn cb_modification<V>(ctxt: *mut c_void, offset: u64) -> ModificationStatus
748 where
749 V: CustomBinaryView,
750 {
751 ffi_wrap!("BinaryViewBase::modification_status", unsafe {
752 let context = &*(ctxt as *mut CustomViewContext<V>);
753 context.assume_init_ref().modification_status(offset)
754 })
755 }
756
757 extern "C" fn cb_offset_valid<V>(ctxt: *mut c_void, offset: u64) -> bool
758 where
759 V: CustomBinaryView,
760 {
761 ffi_wrap!("BinaryViewBase::offset_valid", unsafe {
762 let context = &*(ctxt as *mut CustomViewContext<V>);
763 context.assume_init_ref().offset_valid(offset)
764 })
765 }
766
767 extern "C" fn cb_offset_readable<V>(ctxt: *mut c_void, offset: u64) -> bool
768 where
769 V: CustomBinaryView,
770 {
771 ffi_wrap!("BinaryViewBase::readable", unsafe {
772 let context = &*(ctxt as *mut CustomViewContext<V>);
773 context.assume_init_ref().offset_readable(offset)
774 })
775 }
776
777 extern "C" fn cb_offset_writable<V>(ctxt: *mut c_void, offset: u64) -> bool
778 where
779 V: CustomBinaryView,
780 {
781 ffi_wrap!("BinaryViewBase::writable", unsafe {
782 let context = &*(ctxt as *mut CustomViewContext<V>);
783 context.assume_init_ref().offset_writable(offset)
784 })
785 }
786
787 extern "C" fn cb_offset_executable<V>(ctxt: *mut c_void, offset: u64) -> bool
788 where
789 V: CustomBinaryView,
790 {
791 ffi_wrap!("BinaryViewBase::offset_executable", unsafe {
792 let context = &*(ctxt as *mut CustomViewContext<V>);
793 context.assume_init_ref().offset_executable(offset)
794 })
795 }
796
797 extern "C" fn cb_offset_backed_by_file<V>(ctxt: *mut c_void, offset: u64) -> bool
798 where
799 V: CustomBinaryView,
800 {
801 ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe {
802 let context = &*(ctxt as *mut CustomViewContext<V>);
803 context.assume_init_ref().offset_backed_by_file(offset)
804 })
805 }
806
807 extern "C" fn cb_next_valid_offset<V>(ctxt: *mut c_void, offset: u64) -> u64
808 where
809 V: CustomBinaryView,
810 {
811 ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe {
812 let context = &*(ctxt as *mut CustomViewContext<V>);
813 context.assume_init_ref().next_valid_offset_after(offset)
814 })
815 }
816
817 extern "C" fn cb_start<V>(ctxt: *mut c_void) -> u64
818 where
819 V: CustomBinaryView,
820 {
821 ffi_wrap!("BinaryViewBase::start", unsafe {
822 let context = &*(ctxt as *mut CustomViewContext<V>);
823 context.assume_init_ref().start()
824 })
825 }
826
827 extern "C" fn cb_length<V>(ctxt: *mut c_void) -> u64
828 where
829 V: CustomBinaryView,
830 {
831 ffi_wrap!("BinaryViewBase::len", unsafe {
832 let context = &*(ctxt as *mut CustomViewContext<V>);
833 context.assume_init_ref().len()
834 })
835 }
836
837 extern "C" fn cb_entry_point<V>(ctxt: *mut c_void) -> u64
838 where
839 V: CustomBinaryView,
840 {
841 ffi_wrap!("BinaryViewBase::entry_point", unsafe {
842 let context = &*(ctxt as *mut CustomViewContext<V>);
843 context.assume_init_ref().entry_point()
844 })
845 }
846
847 extern "C" fn cb_executable<V>(ctxt: *mut c_void) -> bool
848 where
849 V: CustomBinaryView,
850 {
851 ffi_wrap!("BinaryViewBase::executable", unsafe {
852 let context = &*(ctxt as *mut CustomViewContext<V>);
853 context.assume_init_ref().executable()
854 })
855 }
856
857 extern "C" fn cb_endianness<V>(ctxt: *mut c_void) -> Endianness
858 where
859 V: CustomBinaryView,
860 {
861 ffi_wrap!("BinaryViewBase::default_endianness", unsafe {
862 let context = &*(ctxt as *mut CustomViewContext<V>);
863
864 context.assume_init_ref().default_endianness()
865 })
866 }
867
868 extern "C" fn cb_relocatable<V>(ctxt: *mut c_void) -> bool
869 where
870 V: CustomBinaryView,
871 {
872 ffi_wrap!("BinaryViewBase::relocatable", unsafe {
873 let context = &*(ctxt as *mut CustomViewContext<V>);
874
875 context.assume_init_ref().relocatable()
876 })
877 }
878
879 extern "C" fn cb_address_size<V>(ctxt: *mut c_void) -> usize
880 where
881 V: CustomBinaryView,
882 {
883 ffi_wrap!("BinaryViewBase::address_size", unsafe {
884 let context = &*(ctxt as *mut CustomViewContext<V>);
885
886 context.assume_init_ref().address_size()
887 })
888 }
889
890 extern "C" fn cb_save<V>(ctxt: *mut c_void, _fa: *mut BNFileAccessor) -> bool
891 where
892 V: CustomBinaryView,
893 {
894 ffi_wrap!("BinaryViewBase::save", unsafe {
895 let _context = &*(ctxt as *mut CustomViewContext<V>);
896 false
897 })
898 }
899
900 let ctxt = Box::new(CustomViewContext::<V> {
901 raw_handle: ptr::null_mut(),
902 state: CustomViewContextState::Uninitialized { args: view_args },
903 });
904
905 let ctxt = Box::into_raw(ctxt);
906
907 let mut bn_obj = BNCustomBinaryView {
908 context: ctxt as *mut _,
909 init: Some(cb_init::<V>),
910 freeObject: Some(cb_free_object::<V>),
911 externalRefTaken: None,
912 externalRefReleased: None,
913 read: Some(cb_read::<V>),
914 write: Some(cb_write::<V>),
915 insert: Some(cb_insert::<V>),
916 remove: Some(cb_remove::<V>),
917 getModification: Some(cb_modification::<V>),
918 isValidOffset: Some(cb_offset_valid::<V>),
919 isOffsetReadable: Some(cb_offset_readable::<V>),
920 isOffsetWritable: Some(cb_offset_writable::<V>),
921 isOffsetExecutable: Some(cb_offset_executable::<V>),
922 isOffsetBackedByFile: Some(cb_offset_backed_by_file::<V>),
923 getNextValidOffset: Some(cb_next_valid_offset::<V>),
924 getStart: Some(cb_start::<V>),
925 getLength: Some(cb_length::<V>),
926 getEntryPoint: Some(cb_entry_point::<V>),
927 isExecutable: Some(cb_executable::<V>),
928 getDefaultEndianness: Some(cb_endianness::<V>),
929 isRelocatable: Some(cb_relocatable::<V>),
930 getAddressSize: Some(cb_address_size::<V>),
931 save: Some(cb_save::<V>),
932 onAfterSnapshotDataApplied: Some(cb_on_after_snapshot_data_applied::<V>),
933 };
934
935 let view_name = view_name.to_cstr();
936 unsafe {
937 let res = BNCreateCustomBinaryView(
938 view_name.as_ptr(),
939 file.handle,
940 parent.handle,
941 &mut bn_obj,
942 );
943 assert!(
944 !res.is_null(),
945 "BNCreateCustomBinaryView cannot return null"
946 );
947 (*ctxt).raw_handle = res;
948 Ok(CustomView {
949 handle: BinaryView::ref_from_raw(res),
950 _builder: PhantomData,
951 })
952 }
953 }
954
955 pub fn wrap_existing(self, wrapped_view: Ref<BinaryView>) -> Result<CustomView<'a>> {
956 Ok(CustomView {
957 handle: wrapped_view,
958 _builder: PhantomData,
959 })
960 }
961}