Skip to content

Commit 2a70d41

Browse files
committed
implement rust custom data renderer
1 parent 0493db0 commit 2a70d41

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

rust/src/data_renderer.rs

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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

Comments
 (0)