1use binaryninjacore_sys::*;
18use std::ffi::{c_char, c_void};
19use std::ptr;
20
21use crate::architecture::{ArchitectureExt, CoreArchitecture};
22use crate::binary_view::BinaryView;
23use crate::platform::Platform;
24use crate::qualified_name::QualifiedName;
25use crate::rc::*;
26use crate::string::{raw_to_string, BnString, IntoCStr};
27use crate::types::Type;
28
29pub type Result<R> = std::result::Result<R, ()>;
30
31fn msvc_demangler() -> *mut BNDemangler {
32 unsafe { BNGetMSVCDemangler() }
33}
34
35fn gnu3_demangler() -> *mut BNDemangler {
36 unsafe { BNGetGNU3Demangler() }
37}
38
39fn llvm_demangler() -> *mut BNDemangler {
40 unsafe { BNGetLLVMDemangler() }
41}
42
43#[derive(Clone, Debug)]
45pub struct DemanglerConfig {
46 pub platform: Option<Ref<Platform>>,
47 pub view: Option<Ref<BinaryView>>,
48 pub simplify_templates: bool,
49}
50
51impl Default for DemanglerConfig {
52 fn default() -> Self {
53 let config = unsafe { BNGetDefaultDemanglerConfig() };
54 Self::from_api_object(&config)
55 }
56}
57
58impl DemanglerConfig {
59 pub fn for_platform(platform: &Platform, simplify_templates: bool) -> Self {
60 let config =
61 unsafe { BNGetDemanglerConfigForPlatform(platform.handle, simplify_templates) };
62 Self::from_api_object(&config)
63 }
64
65 pub fn for_binary_view(view: &BinaryView) -> Self {
66 let config = unsafe { BNGetDemanglerConfigForBinaryView(view.handle) };
67 Self::from_api_object(&config)
68 }
69
70 pub(crate) fn from_api_object(config: &BNDemanglerConfig) -> Self {
71 let platform = match config.platform.is_null() {
72 true => None,
73 false => {
74 Some(unsafe { Platform::ref_from_raw(BNNewPlatformReference(config.platform)) })
75 }
76 };
77 let view = match config.view.is_null() {
78 true => None,
79 false => Some(unsafe { BinaryView::ref_from_raw(BNNewViewReference(config.view)) }),
80 };
81 Self {
82 platform,
83 view,
84 simplify_templates: config.simplifyTemplates,
85 }
86 }
87
88 pub fn get_platform(&self) -> Ref<Platform> {
89 self.platform
90 .clone()
91 .or_else(|| Self::default().platform)
92 .expect("default demangler config has no platform")
93 }
94
95 pub(crate) fn to_api_object(&self) -> BNDemanglerConfig {
96 let platform = self.get_platform();
97 BNDemanglerConfig {
98 platform: platform.handle,
99 view: self
100 .view
101 .as_ref()
102 .map(|view| view.handle)
103 .unwrap_or(ptr::null_mut()),
104 simplifyTemplates: self.simplify_templates,
105 }
106 }
107}
108
109#[derive(Clone, Debug, PartialEq, Eq)]
111pub struct DemanglerResult {
112 pub name: QualifiedName,
113 pub ty: Option<Ref<Type>>,
114}
115
116pub type DemangleResult = DemanglerResult;
118
119impl DemanglerResult {
120 pub fn new(name: impl Into<QualifiedName>, ty: Option<Ref<Type>>) -> Self {
121 Self {
122 name: name.into(),
123 ty,
124 }
125 }
126
127 pub(crate) fn from_api_object(result: &BNDemanglerResult) -> Self {
128 let ty = match result.type_.is_null() {
129 true => None,
130 false => Some(unsafe { Type::ref_from_raw(BNNewTypeReference(result.type_)) }),
132 };
133 Self {
134 name: QualifiedName::from_raw(&result.name),
135 ty,
136 }
137 }
138
139 pub(crate) fn from_api_object_and_free(result: &mut BNDemanglerResult) -> Self {
140 let demangler_result = Self::from_api_object(result);
141 unsafe { BNFreeDemanglerResult(result) };
142 demangler_result
143 }
144
145 pub(crate) fn to_api_object(&self) -> BNDemanglerResult {
146 BNDemanglerResult {
147 name: QualifiedName::into_raw(self.name.clone()),
148 type_: self
149 .ty
150 .as_ref()
151 .map(|ty| unsafe { BNNewTypeReference(ty.handle) })
152 .unwrap_or(ptr::null_mut()),
153 }
154 }
155
156 pub fn into_tuple(self) -> (QualifiedName, Option<Ref<Type>>) {
157 (self.name, self.ty)
158 }
159}
160
161impl From<(QualifiedName, Option<Ref<Type>>)> for DemanglerResult {
162 fn from(value: (QualifiedName, Option<Ref<Type>>)) -> Self {
163 Self {
164 name: value.0,
165 ty: value.1,
166 }
167 }
168}
169
170impl From<DemanglerResult> for (QualifiedName, Option<Ref<Type>>) {
171 fn from(value: DemanglerResult) -> Self {
172 value.into_tuple()
173 }
174}
175
176fn collect_demangler_result(res: bool, result: &mut BNDemanglerResult) -> Option<DemanglerResult> {
177 match res {
178 true => Some(DemanglerResult::from_api_object_and_free(result)),
179 false => None,
180 }
181}
182
183fn demangle_with_demangler(
184 demangler: *mut BNDemangler,
185 mangled_name: &str,
186 config: &DemanglerConfig,
187) -> Option<DemanglerResult> {
188 if demangler.is_null() {
189 return None;
190 }
191
192 let mangled_name = mangled_name.to_cstr();
193 let api_config = config.to_api_object();
194 let mut result = BNDemanglerResult::default();
195 let res = unsafe {
196 BNDemangleWithDemangler(demangler, mangled_name.as_ptr(), &api_config, &mut result)
197 };
198 collect_demangler_result(res, &mut result)
199}
200
201pub fn demangle_any(mangled_name: &str, config: &DemanglerConfig) -> Option<DemanglerResult> {
202 let mangled_name = mangled_name.to_cstr();
203 let api_config = config.to_api_object();
204 let mut result = BNDemanglerResult::default();
205 let res = unsafe { BNDemangle(mangled_name.as_ptr(), &api_config, &mut result) };
206 collect_demangler_result(res, &mut result)
207}
208
209pub fn demangle_generic(
210 arch: &CoreArchitecture,
211 mangled_name: &str,
212 view: Option<&BinaryView>,
213 simplify: bool,
214) -> Option<DemanglerResult> {
215 let mut config = match view {
216 Some(view) => DemanglerConfig::for_binary_view(view),
217 None => match arch.standalone_platform() {
218 Some(platform) => DemanglerConfig::for_platform(&platform, simplify),
219 None => DemanglerConfig::default(),
220 },
221 };
222 config.simplify_templates = simplify;
223 demangle_any(mangled_name, &config)
224}
225
226pub fn demangle_llvm(mangled_name: &str, simplify: bool) -> Option<DemanglerResult> {
227 let config = DemanglerConfig {
228 simplify_templates: simplify,
229 ..DemanglerConfig::default()
230 };
231 demangle_llvm_with_config(mangled_name, &config)
232}
233
234pub fn demangle_llvm_with_config(
235 mangled_name: &str,
236 config: &DemanglerConfig,
237) -> Option<DemanglerResult> {
238 demangle_with_demangler(llvm_demangler(), mangled_name, config)
239}
240
241pub fn demangle_gnu3(
242 arch: &CoreArchitecture,
243 mangled_name: &str,
244 simplify: bool,
245) -> Option<DemanglerResult> {
246 let mut config = arch
247 .standalone_platform()
248 .map(|platform| DemanglerConfig::for_platform(&platform, simplify))
249 .unwrap_or_default();
250 config.simplify_templates = simplify;
251 demangle_gnu3_with_config(mangled_name, &config)
252}
253
254pub fn demangle_gnu3_with_config(
255 mangled_name: &str,
256 config: &DemanglerConfig,
257) -> Option<DemanglerResult> {
258 demangle_with_demangler(gnu3_demangler(), mangled_name, config)
259}
260
261pub fn demangle_ms(
262 arch: &CoreArchitecture,
263 mangled_name: &str,
264 simplify: bool,
265) -> Option<DemanglerResult> {
266 let mut config = arch
267 .standalone_platform()
268 .map(|platform| DemanglerConfig::for_platform(&platform, simplify))
269 .unwrap_or_default();
270 config.simplify_templates = simplify;
271 demangle_ms_with_config(mangled_name, &config)
272}
273
274pub fn demangle_ms_with_config(
275 mangled_name: &str,
276 config: &DemanglerConfig,
277) -> Option<DemanglerResult> {
278 demangle_with_demangler(msvc_demangler(), mangled_name, config)
279}
280
281pub fn simplify_demangled_template_name(name: impl Into<QualifiedName>) -> QualifiedName {
282 let name = name.into();
283 let raw_name = QualifiedName::into_raw(name.clone());
284 let mut result = BNQualifiedName::default();
285 let ok = unsafe { BNSimplifyDemangledTemplateName(&raw_name, &mut result) };
286 QualifiedName::free_raw(raw_name);
287 if ok {
288 QualifiedName::from_owned_raw(result)
289 } else {
290 name
291 }
292}
293
294#[derive(PartialEq, Eq, Hash)]
295pub struct Demangler {
296 pub(crate) handle: *mut BNDemangler,
297}
298
299impl Demangler {
300 pub(crate) unsafe fn from_raw(handle: *mut BNDemangler) -> Self {
301 debug_assert!(!handle.is_null());
302 Self { handle }
303 }
304
305 pub fn list() -> Array<Self> {
306 let mut count: usize = 0;
307 let demanglers = unsafe { BNGetDemanglerList(&mut count) };
308 unsafe { Array::<Demangler>::new(demanglers, count, ()) }
309 }
310
311 pub fn is_mangled_string(&self, name: &str) -> bool {
312 let bytes = name.to_cstr();
313 unsafe { BNIsDemanglerMangledName(self.handle, bytes.as_ref().as_ptr() as *const _) }
314 }
315
316 pub fn demangle(&self, name: &str, config: &DemanglerConfig) -> Option<DemanglerResult> {
317 demangle_with_demangler(self.handle, name, config)
318 }
319
320 pub fn name(&self) -> String {
321 unsafe { BnString::into_string(BNGetDemanglerName(self.handle)) }
322 }
323
324 pub fn from_name(name: &str) -> Option<Self> {
325 let name_bytes = name.to_cstr();
326 let demangler = unsafe { BNGetDemanglerByName(name_bytes.as_ref().as_ptr() as *const _) };
327 if demangler.is_null() {
328 None
329 } else {
330 Some(unsafe { Demangler::from_raw(demangler) })
331 }
332 }
333
334 pub fn register<C: CustomDemangler>(name: &str, demangler: C) -> bool {
335 extern "C" fn cb_is_mangled_string<C>(ctxt: *mut c_void, name: *const c_char) -> bool
336 where
337 C: CustomDemangler,
338 {
339 ffi_wrap!("CustomDemangler::cb_is_mangled_string", unsafe {
340 let cmd = &*(ctxt as *const C);
341 let Some(name) = raw_to_string(name) else {
342 return false;
343 };
344 cmd.is_mangled_string(&name)
345 })
346 }
347 extern "C" fn cb_demangle<C>(
348 ctxt: *mut c_void,
349 name: *const c_char,
350 config: *const BNDemanglerConfig,
351 result: *mut BNDemanglerResult,
352 ) -> bool
353 where
354 C: CustomDemangler,
355 {
356 ffi_wrap!("CustomDemangler::cb_demangle", unsafe {
357 if result.is_null() {
358 return false;
359 }
360
361 let cmd = &*(ctxt as *const C);
362 let Some(name) = raw_to_string(name) else {
363 return false;
364 };
365 let config = match config.as_ref() {
366 Some(config) => DemanglerConfig::from_api_object(config),
367 None => DemanglerConfig::default(),
368 };
369
370 match cmd.demangle(&name, &config) {
371 Some(demangle_result) => {
372 *result = demangle_result.to_api_object();
373 true
374 }
375 None => false,
376 }
377 })
378 }
379
380 extern "C" fn cb_free_result(_ctxt: *mut c_void, result: *mut BNDemanglerResult) {
381 ffi_wrap!("CustomDemangler::cb_free_result", unsafe {
382 if !result.is_null() {
383 BNFreeDemanglerResult(result);
384 }
385 })
386 }
387
388 let name = name.to_cstr();
389 let name_ptr = name.as_ptr();
390 let ctxt = Box::into_raw(Box::new(demangler));
391
392 let callbacks = Box::into_raw(Box::new(BNDemanglerCallbacks {
393 context: ctxt as *mut c_void,
394 isMangledString: Some(cb_is_mangled_string::<C>),
395 demangle: Some(cb_demangle::<C>),
396 freeResult: Some(cb_free_result),
397 }));
398
399 let handle = unsafe { BNRegisterDemangler(name_ptr, callbacks) };
400 if handle.is_null() {
401 unsafe {
402 drop(Box::from_raw(ctxt));
403 drop(Box::from_raw(callbacks));
404 }
405 false
406 } else {
407 true
408 }
409 }
410
411 pub fn demangle_any(name: &str, config: &DemanglerConfig) -> Option<DemanglerResult> {
412 demangle_any(name, config)
413 }
414
415 pub fn promote(demangler: &Demangler) -> bool {
416 if demangler.handle.is_null() {
417 return false;
418 }
419 unsafe { BNPromoteDemangler(demangler.handle) }
420 }
421}
422
423unsafe impl Sync for Demangler {}
424
425unsafe impl Send for Demangler {}
426
427impl CoreArrayProvider for Demangler {
428 type Raw = *mut BNDemangler;
429 type Context = ();
430 type Wrapped<'a> = Demangler;
431}
432
433unsafe impl CoreArrayProviderInner for Demangler {
434 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
435 BNFreeDemanglerList(raw);
436 }
437
438 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
439 Demangler::from_raw(*raw)
440 }
441}
442
443pub trait CustomDemangler: 'static + Sync {
444 fn is_mangled_string(&self, name: &str) -> bool;
445
446 fn demangle(&self, name: &str, config: &DemanglerConfig) -> Option<DemanglerResult>;
447}