1use binaryninjacore_sys::*;
18use std::ffi::{c_char, c_void};
19
20use crate::architecture::CoreArchitecture;
21use crate::binary_view::BinaryView;
22use crate::string::{raw_to_string, BnString, IntoCStr};
23use crate::types::{QualifiedName, Type};
24
25use crate::rc::*;
26
27pub type Result<R> = std::result::Result<R, ()>;
28
29pub fn demangle_generic(
30 arch: &CoreArchitecture,
31 mangled_name: &str,
32 view: Option<&BinaryView>,
33 simplify: bool,
34) -> Option<(QualifiedName, Option<Ref<Type>>)> {
35 let mangled_name = mangled_name.to_cstr();
36 let mut out_type: *mut BNType = std::ptr::null_mut();
37 let mut out_name = BNQualifiedName::default();
38 let res = unsafe {
39 BNDemangleGeneric(
40 arch.handle,
41 mangled_name.as_ptr(),
42 &mut out_type,
43 &mut out_name,
44 view.map(|v| v.handle).unwrap_or(std::ptr::null_mut()),
45 simplify,
46 )
47 };
48
49 if res {
50 let out_type = match out_type.is_null() {
51 true => None,
52 false => Some(unsafe { Type::ref_from_raw(out_type) }),
53 };
54 Some((QualifiedName::from_owned_raw(out_name), out_type))
55 } else {
56 None
57 }
58}
59
60pub fn demangle_llvm(mangled_name: &str, simplify: bool) -> Option<QualifiedName> {
61 let mangled_name = mangled_name.to_cstr();
62 let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut();
63 let mut out_size: usize = 0;
64 let res = unsafe {
65 BNDemangleLLVM(
66 mangled_name.as_ptr(),
67 &mut out_name,
68 &mut out_size,
69 simplify,
70 )
71 };
72
73 match res {
74 true => {
75 assert!(!out_name.is_null());
76 let names: Vec<_> = unsafe { ArrayGuard::<BnString>::new(out_name, out_size, ()) }
77 .iter()
78 .map(str::to_string)
79 .collect();
80 unsafe { BNFreeDemangledName(&mut out_name, out_size) };
81
82 Some(names.into())
83 }
84 false => None,
85 }
86}
87
88pub fn demangle_gnu3(
89 arch: &CoreArchitecture,
90 mangled_name: &str,
91 simplify: bool,
92) -> Option<(QualifiedName, Option<Ref<Type>>)> {
93 let mangled_name = mangled_name.to_cstr();
94 let mut out_type: *mut BNType = std::ptr::null_mut();
95 let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut();
96 let mut out_size: usize = 0;
97 let res = unsafe {
98 BNDemangleGNU3(
99 arch.handle,
100 mangled_name.as_ptr(),
101 &mut out_type,
102 &mut out_name,
103 &mut out_size,
104 simplify,
105 )
106 };
107
108 match res {
109 true => {
110 assert!(!out_name.is_null());
111 let names: Vec<_> = unsafe { ArrayGuard::<BnString>::new(out_name, out_size, ()) }
112 .iter()
113 .map(str::to_string)
114 .collect();
115 unsafe { BNFreeDemangledName(&mut out_name, out_size) };
116
117 let out_type = match out_type.is_null() {
118 true => None,
119 false => Some(unsafe { Type::ref_from_raw(out_type) }),
120 };
121
122 Some((names.into(), out_type))
123 }
124 false => None,
125 }
126}
127
128pub fn demangle_ms(
129 arch: &CoreArchitecture,
130 mangled_name: &str,
131 simplify: bool,
132) -> Option<(QualifiedName, Option<Ref<Type>>)> {
133 let mangled_name = mangled_name.to_cstr();
134 let mut out_type: *mut BNType = std::ptr::null_mut();
135 let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut();
136 let mut out_size: usize = 0;
137 let res = unsafe {
138 BNDemangleMS(
139 arch.handle,
140 mangled_name.as_ptr(),
141 &mut out_type,
142 &mut out_name,
143 &mut out_size,
144 simplify,
145 )
146 };
147
148 match res {
149 true => {
150 assert!(!out_name.is_null());
151 let names: Vec<_> = unsafe { ArrayGuard::<BnString>::new(out_name, out_size, ()) }
152 .iter()
153 .map(str::to_string)
154 .collect();
155 unsafe { BNFreeDemangledName(&mut out_name, out_size) };
156
157 let out_type = match out_type.is_null() {
158 true => None,
159 false => Some(unsafe { Type::ref_from_raw(out_type) }),
160 };
161
162 Some((names.into(), out_type))
163 }
164 false => None,
165 }
166}
167
168#[derive(PartialEq, Eq, Hash)]
169pub struct Demangler {
170 pub(crate) handle: *mut BNDemangler,
171}
172
173impl Demangler {
174 pub(crate) unsafe fn from_raw(handle: *mut BNDemangler) -> Self {
175 debug_assert!(!handle.is_null());
176 Self { handle }
177 }
178
179 pub fn list() -> Array<Self> {
180 let mut count: usize = 0;
181 let demanglers = unsafe { BNGetDemanglerList(&mut count) };
182 unsafe { Array::<Demangler>::new(demanglers, count, ()) }
183 }
184
185 pub fn is_mangled_string(&self, name: &str) -> bool {
186 let bytes = name.to_cstr();
187 unsafe { BNIsDemanglerMangledName(self.handle, bytes.as_ref().as_ptr() as *const _) }
188 }
189
190 pub fn demangle(
191 &self,
192 arch: &CoreArchitecture,
193 name: &str,
194 view: Option<&BinaryView>,
195 ) -> Option<(QualifiedName, Option<Ref<Type>>)> {
196 let name_bytes = name.to_cstr();
197
198 let mut out_type = std::ptr::null_mut();
199 let mut out_var_name = BNQualifiedName::default();
200
201 let view_ptr = match view {
202 Some(v) => v.handle,
203 None => std::ptr::null_mut(),
204 };
205
206 let res = unsafe {
207 BNDemanglerDemangle(
208 self.handle,
209 arch.handle,
210 name_bytes.as_ref().as_ptr() as *const _,
211 &mut out_type,
212 &mut out_var_name,
213 view_ptr,
214 )
215 };
216
217 match res {
218 true => {
219 let var_type = match out_type.is_null() {
220 true => None,
221 false => Some(unsafe { Type::ref_from_raw(out_type) }),
222 };
223
224 Some((QualifiedName::from_owned_raw(out_var_name), var_type))
225 }
226 false => None,
227 }
228 }
229
230 pub fn name(&self) -> String {
231 unsafe { BnString::into_string(BNGetDemanglerName(self.handle)) }
232 }
233
234 pub fn from_name(name: &str) -> Option<Self> {
235 let name_bytes = name.to_cstr();
236 let demangler = unsafe { BNGetDemanglerByName(name_bytes.as_ref().as_ptr() as *const _) };
237 if demangler.is_null() {
238 None
239 } else {
240 Some(unsafe { Demangler::from_raw(demangler) })
241 }
242 }
243
244 pub fn register<C: CustomDemangler>(name: &str, demangler: C) -> Self {
245 extern "C" fn cb_is_mangled_string<C>(ctxt: *mut c_void, name: *const c_char) -> bool
246 where
247 C: CustomDemangler,
248 {
249 ffi_wrap!("CustomDemangler::cb_is_mangled_string", unsafe {
250 let cmd = &*(ctxt as *const C);
251 let Some(name) = raw_to_string(name) else {
252 return false;
253 };
254 cmd.is_mangled_string(&name)
255 })
256 }
257 extern "C" fn cb_demangle<C>(
258 ctxt: *mut c_void,
259 arch: *mut BNArchitecture,
260 name: *const c_char,
261 out_type: *mut *mut BNType,
262 out_var_name: *mut BNQualifiedName,
263 view: *mut BNBinaryView,
264 ) -> bool
265 where
266 C: CustomDemangler,
267 {
268 ffi_wrap!("CustomDemangler::cb_demangle", unsafe {
269 let cmd = &*(ctxt as *const C);
270 let arch = CoreArchitecture::from_raw(arch);
271 let Some(name) = raw_to_string(name) else {
272 return false;
273 };
274 let view = match view.is_null() {
275 false => Some(BinaryView::from_raw(view).to_owned()),
276 true => None,
277 };
278
279 match cmd.demangle(&arch, &name, view) {
280 Some((name, ty)) => {
281 *out_type = match ty {
283 Some(t) => Ref::into_raw(t).handle,
284 None => std::ptr::null_mut(),
285 };
286 *out_var_name = QualifiedName::into_raw(name);
288 true
289 }
290 None => false,
291 }
292 })
293 }
294
295 extern "C" fn cb_free_var_name(_ctxt: *mut c_void, name: *mut BNQualifiedName) {
296 ffi_wrap!("CustomDemangler::cb_free_var_name", unsafe {
297 QualifiedName::free_raw(*name)
299 })
300 }
301
302 let name = name.to_cstr();
303 let name_ptr = name.as_ptr();
304 let ctxt = Box::into_raw(Box::new(demangler));
305
306 let callbacks = BNDemanglerCallbacks {
307 context: ctxt as *mut c_void,
308 isMangledString: Some(cb_is_mangled_string::<C>),
309 demangle: Some(cb_demangle::<C>),
310 freeVarName: Some(cb_free_var_name),
311 };
312
313 unsafe {
314 Demangler::from_raw(BNRegisterDemangler(
315 name_ptr,
316 Box::leak(Box::new(callbacks)),
317 ))
318 }
319 }
320
321 pub fn promote(demangler: &Demangler) {
322 unsafe {
323 BNPromoteDemangler(demangler.handle);
324 }
325 }
326}
327
328unsafe impl Sync for Demangler {}
329
330unsafe impl Send for Demangler {}
331
332impl CoreArrayProvider for Demangler {
333 type Raw = *mut BNDemangler;
334 type Context = ();
335 type Wrapped<'a> = Demangler;
336}
337
338unsafe impl CoreArrayProviderInner for Demangler {
339 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
340 BNFreeDemanglerList(raw);
341 }
342
343 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
344 Demangler::from_raw(*raw)
345 }
346}
347
348pub trait CustomDemangler: 'static + Sync {
349 fn is_mangled_string(&self, name: &str) -> bool;
350
351 fn demangle(
352 &self,
353 arch: &CoreArchitecture,
354 name: &str,
355 view: Option<Ref<BinaryView>>,
356 ) -> Option<(QualifiedName, Option<Ref<Type>>)>;
357}