|
| 1 | +use core::ffi; |
| 2 | + |
| 3 | +use binaryninjacore_sys::*; |
| 4 | + |
| 5 | +use crate::binary_view::BinaryView; |
| 6 | +use crate::disassembly::{DisassemblyTextLine, InstructionTextToken}; |
| 7 | +use crate::rc::{Ref, RefCountable}; |
| 8 | +use crate::types::Type; |
| 9 | + |
| 10 | +// NOTE the type_ inside the context can be both owned or borrowed, because |
| 11 | +// this type only exist as a reference and is never created by itself (AKA |
| 12 | +// don't have a *from_raw function, it don't need to worry about drop it. |
| 13 | +#[repr(transparent)] |
| 14 | +pub struct TypeContext(BNTypeContext); |
| 15 | + |
| 16 | +impl TypeContext { |
| 17 | + pub fn type_(&self) -> &Type { |
| 18 | + // SAFETY Type and `*mut BNType` are transparent |
| 19 | + unsafe { core::mem::transmute::<&*mut BNType, &Type>(&self.0.type_) } |
| 20 | + } |
| 21 | + |
| 22 | + pub fn offset(&self) -> usize { |
| 23 | + self.0.offset |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +pub trait CustomDataRenderer: Sized + Sync + Send + 'static { |
| 28 | + fn is_valid_for_data( |
| 29 | + &self, |
| 30 | + view: &BinaryView, |
| 31 | + addr: u64, |
| 32 | + type_: &Type, |
| 33 | + types: &[TypeContext], |
| 34 | + ) -> bool; |
| 35 | + fn lines_for_data( |
| 36 | + &self, |
| 37 | + view: &BinaryView, |
| 38 | + addr: u64, |
| 39 | + type_: &Type, |
| 40 | + prefix: &InstructionTextToken, |
| 41 | + prefix_count: usize, |
| 42 | + width: usize, |
| 43 | + types_ctx: &[TypeContext], |
| 44 | + language: &str, |
| 45 | + ) -> Vec<DisassemblyTextLine>; |
| 46 | +} |
| 47 | + |
| 48 | +trait CustomDataRendererFFI: CustomDataRenderer { |
| 49 | + unsafe extern "C" fn free_object_ffi(ctxt: *mut ffi::c_void) { |
| 50 | + drop(Box::from_raw(ctxt as *mut Self)) |
| 51 | + } |
| 52 | + |
| 53 | + unsafe extern "C" fn is_valid_for_data_ffi( |
| 54 | + ctxt: *mut ffi::c_void, |
| 55 | + view: *mut BNBinaryView, |
| 56 | + addr: u64, |
| 57 | + type_: *mut BNType, |
| 58 | + type_ctx: *mut BNTypeContext, |
| 59 | + ctx_count: usize, |
| 60 | + ) -> bool { |
| 61 | + let ctxt = ctxt as *mut Self; |
| 62 | + // SAFETY BNTypeContext and TypeContext are transparent |
| 63 | + let types = core::slice::from_raw_parts(type_ctx as *mut TypeContext, ctx_count); |
| 64 | + (*ctxt).is_valid_for_data( |
| 65 | + &BinaryView::from_raw(view), |
| 66 | + addr, |
| 67 | + &Type::from_raw(type_), |
| 68 | + types, |
| 69 | + ) |
| 70 | + } |
| 71 | + |
| 72 | + unsafe extern "C" fn get_lines_for_data_ffi( |
| 73 | + ctxt: *mut ffi::c_void, |
| 74 | + view: *mut BNBinaryView, |
| 75 | + addr: u64, |
| 76 | + type_: *mut BNType, |
| 77 | + prefix: *const BNInstructionTextToken, |
| 78 | + prefix_count: usize, |
| 79 | + width: usize, |
| 80 | + count: *mut usize, |
| 81 | + type_ctx: *mut BNTypeContext, |
| 82 | + ctx_count: usize, |
| 83 | + language: *const ffi::c_char, |
| 84 | + ) -> *mut BNDisassemblyTextLine { |
| 85 | + let ctxt = ctxt as *mut Self; |
| 86 | + // SAFETY BNTypeContext and TypeContext are transparent |
| 87 | + let types = core::slice::from_raw_parts(type_ctx as *mut TypeContext, ctx_count); |
| 88 | + let result = (*ctxt).lines_for_data( |
| 89 | + &BinaryView::from_raw(view), |
| 90 | + addr, |
| 91 | + &Type::from_raw(type_), |
| 92 | + &InstructionTextToken::from_raw(&*prefix), |
| 93 | + prefix_count, |
| 94 | + width, |
| 95 | + types, |
| 96 | + ffi::CStr::from_ptr(language).to_str().unwrap(), |
| 97 | + ); |
| 98 | + let result: Box<[BNDisassemblyTextLine]> = result |
| 99 | + .into_iter() |
| 100 | + .map(DisassemblyTextLine::into_raw) |
| 101 | + .collect(); |
| 102 | + *count = result.len(); |
| 103 | + Box::leak(result).as_mut_ptr() |
| 104 | + } |
| 105 | + |
| 106 | + unsafe extern "C" fn free_lines_ffi( |
| 107 | + _ctx: *mut ffi::c_void, |
| 108 | + lines: *mut BNDisassemblyTextLine, |
| 109 | + count: usize, |
| 110 | + ) { |
| 111 | + let lines = Box::from_raw(core::slice::from_raw_parts_mut(lines, count)); |
| 112 | + drop( |
| 113 | + lines |
| 114 | + .iter() |
| 115 | + .map(DisassemblyTextLine::from_raw) |
| 116 | + .collect::<Box<[_]>>(), |
| 117 | + ); |
| 118 | + } |
| 119 | +} |
| 120 | + |
| 121 | +impl<C: CustomDataRenderer> CustomDataRendererFFI for C {} |
| 122 | + |
| 123 | +pub struct CoreDataRenderer(*mut BNDataRenderer); |
| 124 | + |
| 125 | +impl CoreDataRenderer { |
| 126 | + pub(crate) unsafe fn ref_from_raw(raw: *mut BNDataRenderer) -> Ref<Self> { |
| 127 | + Ref::new(Self(raw)) |
| 128 | + } |
| 129 | + pub(crate) fn as_raw(&self) -> *mut BNDataRenderer { |
| 130 | + self.0 |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +unsafe impl RefCountable for CoreDataRenderer { |
| 135 | + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { |
| 136 | + Self::ref_from_raw(BNNewDataRendererReference(handle.0)) |
| 137 | + } |
| 138 | + |
| 139 | + unsafe fn dec_ref(handle: &Self) { |
| 140 | + BNFreeDataRenderer(handle.0); |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +impl ToOwned for CoreDataRenderer { |
| 145 | + type Owned = Ref<Self>; |
| 146 | + |
| 147 | + fn to_owned(&self) -> Self::Owned { |
| 148 | + unsafe { <Self as RefCountable>::inc_ref(self) } |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | +fn create_custom_data_renderer<C: CustomDataRenderer>(custom: C) -> Ref<CoreDataRenderer> { |
| 153 | + let custom = Box::leak(Box::new(custom)); |
| 154 | + let mut callbacks = BNCustomDataRenderer { |
| 155 | + context: custom as *mut C as *mut ffi::c_void, |
| 156 | + freeObject: Some(<C as CustomDataRendererFFI>::free_object_ffi), |
| 157 | + isValidForData: Some(<C as CustomDataRendererFFI>::is_valid_for_data_ffi), |
| 158 | + getLinesForData: Some(<C as CustomDataRendererFFI>::get_lines_for_data_ffi), |
| 159 | + freeLines: Some(<C as CustomDataRendererFFI>::free_lines_ffi), |
| 160 | + }; |
| 161 | + unsafe { CoreDataRenderer::ref_from_raw(BNCreateDataRenderer(&mut callbacks)) } |
| 162 | +} |
| 163 | + |
| 164 | +pub fn register_generic_data_renderer<C: CustomDataRenderer>(custom: C) -> Ref<CoreDataRenderer> { |
| 165 | + let renderer = create_custom_data_renderer(custom); |
| 166 | + register_generic_renderer(&renderer); |
| 167 | + renderer |
| 168 | +} |
| 169 | + |
| 170 | +pub fn register_specific_data_renderer<C: CustomDataRenderer>(custom: C) -> Ref<CoreDataRenderer> { |
| 171 | + let renderer = create_custom_data_renderer(custom); |
| 172 | + register_specific_renderer(&renderer); |
| 173 | + renderer |
| 174 | +} |
| 175 | + |
| 176 | +#[derive(Clone, Copy)] |
| 177 | +struct DataRendererContainer(*mut BNDataRendererContainer); |
| 178 | + |
| 179 | +impl DataRendererContainer { |
| 180 | + pub(crate) fn as_raw(&self) -> *mut BNDataRendererContainer { |
| 181 | + self.0 |
| 182 | + } |
| 183 | + |
| 184 | + pub fn get() -> Self { |
| 185 | + Self(unsafe { BNGetDataRendererContainer() }) |
| 186 | + } |
| 187 | +} |
| 188 | + |
| 189 | +fn register_generic_renderer(renderer: &CoreDataRenderer) { |
| 190 | + let container = DataRendererContainer::get(); |
| 191 | + unsafe { BNRegisterGenericDataRenderer(container.as_raw(), renderer.as_raw()) } |
| 192 | +} |
| 193 | + |
| 194 | +fn register_specific_renderer(renderer: &CoreDataRenderer) { |
| 195 | + let container = DataRendererContainer::get(); |
| 196 | + unsafe { BNRegisterTypeSpecificDataRenderer(container.as_raw(), renderer.as_raw()) } |
| 197 | +} |
0 commit comments