1use crate::{
18 architecture::{Architecture, CoreArchitecture},
19 calling_convention::CoreCallingConvention,
20 rc::*,
21 string::*,
22 types::{
23 QualifiedName, QualifiedNameAndType, Type, TypeContainer, TypeLibrary, TypeParserError,
24 TypeParserErrorSeverity, TypeParserResult,
25 },
26};
27use binaryninjacore_sys::*;
28use std::fmt::Debug;
29use std::ptr::NonNull;
30use std::{borrow::Borrow, ffi, ptr};
31
32#[derive(PartialEq, Eq, Hash)]
35pub struct Platform {
36 pub(crate) handle: *mut BNPlatform,
37}
38
39unsafe impl Send for Platform {}
40unsafe impl Sync for Platform {}
41
42macro_rules! cc_func {
43 ($get_name:ident, $get_api:ident, $set_name:ident, $set_api:ident) => {
44 pub fn $get_name(&self) -> Option<Ref<CoreCallingConvention>> {
45 let arch = self.arch();
46
47 unsafe {
48 let cc = $get_api(self.handle);
49
50 if cc.is_null() {
51 None
52 } else {
53 Some(CoreCallingConvention::ref_from_raw(
54 cc,
55 arch.as_ref().handle(),
56 ))
57 }
58 }
59 }
60
61 pub fn $set_name(&self, cc: &CoreCallingConvention) {
62 let arch = self.arch();
63
64 assert!(
65 cc.arch_handle.borrow().as_ref().handle == arch.handle,
66 "use of calling convention with non-matching Platform architecture!"
67 );
68
69 unsafe {
70 $set_api(self.handle, cc.handle);
71 }
72 }
73 };
74}
75
76impl Platform {
77 pub unsafe fn from_raw(handle: *mut BNPlatform) -> Self {
78 debug_assert!(!handle.is_null());
79 Self { handle }
80 }
81
82 pub(crate) unsafe fn ref_from_raw(handle: *mut BNPlatform) -> Ref<Self> {
83 debug_assert!(!handle.is_null());
84 Ref::new(Self { handle })
85 }
86
87 pub fn by_name(name: &str) -> Option<Ref<Self>> {
88 let raw_name = name.to_cstr();
89 unsafe {
90 let res = BNGetPlatformByName(raw_name.as_ptr());
91
92 if res.is_null() {
93 None
94 } else {
95 Some(Self::ref_from_raw(res))
96 }
97 }
98 }
99
100 pub fn list_all() -> Array<Platform> {
101 unsafe {
102 let mut count = 0;
103 let handles = BNGetPlatformList(&mut count);
104
105 Array::new(handles, count, ())
106 }
107 }
108
109 pub fn list_by_arch(arch: &CoreArchitecture) -> Array<Platform> {
110 unsafe {
111 let mut count = 0;
112 let handles = BNGetPlatformListByArchitecture(arch.handle, &mut count);
113
114 Array::new(handles, count, ())
115 }
116 }
117
118 pub fn list_by_os(name: &str) -> Array<Platform> {
119 let raw_name = name.to_cstr();
120
121 unsafe {
122 let mut count = 0;
123 let handles = BNGetPlatformListByOS(raw_name.as_ptr(), &mut count);
124
125 Array::new(handles, count, ())
126 }
127 }
128
129 pub fn list_by_os_and_arch(name: &str, arch: &CoreArchitecture) -> Array<Platform> {
130 let raw_name = name.to_cstr();
131
132 unsafe {
133 let mut count = 0;
134 let handles =
135 BNGetPlatformListByOSAndArchitecture(raw_name.as_ptr(), arch.handle, &mut count);
136
137 Array::new(handles, count, ())
138 }
139 }
140
141 pub fn list_available_os() -> Array<BnString> {
142 unsafe {
143 let mut count = 0;
144 let list = BNGetPlatformOSList(&mut count);
145
146 Array::new(list, count, ())
147 }
148 }
149
150 pub fn new<A: Architecture>(arch: &A, name: &str) -> Ref<Self> {
151 let name = name.to_cstr();
152 unsafe {
153 let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ptr());
154 assert!(!handle.is_null());
155 Ref::new(Self { handle })
156 }
157 }
158
159 pub fn name(&self) -> String {
160 unsafe {
161 let raw_name = BNGetPlatformName(self.handle);
162 BnString::into_string(raw_name)
163 }
164 }
165
166 pub fn arch(&self) -> CoreArchitecture {
167 unsafe { CoreArchitecture::from_raw(BNGetPlatformArchitecture(self.handle)) }
168 }
169
170 pub fn address_size(&self) -> usize {
173 unsafe { BNGetPlatformAddressSize(self.handle) }
174 }
175
176 pub fn type_container(&self) -> TypeContainer {
177 let type_container_ptr = NonNull::new(unsafe { BNGetPlatformTypeContainer(self.handle) });
178 unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
182 }
183
184 pub fn get_type_libraries_by_name(&self, name: &str) -> Array<TypeLibrary> {
189 let mut count = 0;
190 let name = name.to_cstr();
191 let result =
192 unsafe { BNGetPlatformTypeLibrariesByName(self.handle, name.as_ptr(), &mut count) };
193 assert!(!result.is_null());
194 unsafe { Array::new(result, count, ()) }
195 }
196
197 pub fn get_type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> {
201 let libraries = self.get_type_libraries_by_name(name);
202 libraries
203 .iter()
204 .find(|lib| lib.name() == name)
205 .map(|lib| lib.to_owned())
206 }
207
208 pub fn register_os(&self, os: &str) {
209 let os = os.to_cstr();
210 unsafe {
211 BNRegisterPlatform(os.as_ptr(), self.handle);
212 }
213 }
214
215 cc_func!(
216 get_default_calling_convention,
217 BNGetPlatformDefaultCallingConvention,
218 set_default_calling_convention,
219 BNRegisterPlatformDefaultCallingConvention
220 );
221
222 cc_func!(
223 get_cdecl_calling_convention,
224 BNGetPlatformCdeclCallingConvention,
225 set_cdecl_calling_convention,
226 BNRegisterPlatformCdeclCallingConvention
227 );
228
229 cc_func!(
230 get_stdcall_calling_convention,
231 BNGetPlatformStdcallCallingConvention,
232 set_stdcall_calling_convention,
233 BNRegisterPlatformStdcallCallingConvention
234 );
235
236 cc_func!(
237 get_fastcall_calling_convention,
238 BNGetPlatformFastcallCallingConvention,
239 set_fastcall_calling_convention,
240 BNRegisterPlatformFastcallCallingConvention
241 );
242
243 cc_func!(
244 get_syscall_convention,
245 BNGetPlatformSystemCallConvention,
246 set_syscall_convention,
247 BNSetPlatformSystemCallConvention
248 );
249
250 pub fn register_calling_convention(&self, cc: &CoreCallingConvention) {
259 let arch = self.arch();
260
261 assert_eq!(
262 cc.arch_handle.handle, arch.handle,
263 "use of calling convention with non-matching Platform architecture!"
264 );
265
266 unsafe {
267 BNRegisterPlatformCallingConvention(self.handle, cc.handle);
268 }
269 }
270
271 pub fn calling_conventions(&self) -> Array<CoreCallingConvention> {
272 unsafe {
273 let mut count = 0;
274 let handles = BNGetPlatformCallingConventions(self.handle, &mut count);
275 Array::new(handles, count, self.arch())
276 }
277 }
278
279 pub fn types(&self) -> Array<QualifiedNameAndType> {
280 unsafe {
281 let mut count = 0;
282 let handles = BNGetPlatformTypes(self.handle, &mut count);
283 Array::new(handles, count, ())
284 }
285 }
286
287 pub fn variables(&self) -> Array<QualifiedNameAndType> {
288 unsafe {
289 let mut count = 0;
290 let handles = BNGetPlatformVariables(self.handle, &mut count);
291 Array::new(handles, count, ())
292 }
293 }
294
295 pub fn functions(&self) -> Array<QualifiedNameAndType> {
296 unsafe {
297 let mut count = 0;
298 let handles = BNGetPlatformFunctions(self.handle, &mut count);
299 Array::new(handles, count, ())
300 }
301 }
302
303 pub fn function_by_name<T: Into<QualifiedName>>(
304 &self,
305 name: T,
306 exact_match: bool,
307 ) -> Option<Ref<Type>> {
308 let mut raw_name = QualifiedName::into_raw(name.into());
309 unsafe {
310 let type_handle = BNGetPlatformFunctionByName(self.handle, &mut raw_name, exact_match);
311 QualifiedName::free_raw(raw_name);
312 if type_handle.is_null() {
313 return None;
314 }
315 Some(Type::ref_from_raw(type_handle))
316 }
317 }
318
319 pub fn preprocess_source(
324 &self,
325 source: &str,
326 file_name: &str,
327 include_dirs: &[BnString],
328 ) -> Result<BnString, TypeParserError> {
329 let source_cstr = BnString::new(source);
330 let file_name_cstr = BnString::new(file_name);
331
332 let mut result = ptr::null_mut();
333 let mut error_string = ptr::null_mut();
334 let success = unsafe {
335 BNPreprocessSource(
336 source_cstr.as_ptr(),
337 file_name_cstr.as_ptr(),
338 &mut result,
339 &mut error_string,
340 include_dirs.as_ptr() as *mut *const ffi::c_char,
341 include_dirs.len(),
342 )
343 };
344
345 if success {
346 assert!(!result.is_null());
347 Ok(unsafe { BnString::from_raw(result) })
348 } else {
349 assert!(!error_string.is_null());
350 Err(TypeParserError::new(
351 TypeParserErrorSeverity::FatalSeverity,
352 unsafe { BnString::into_string(error_string) },
353 file_name.to_string(),
354 0,
355 0,
356 ))
357 }
358 }
359
360 pub fn parse_types_from_source(
362 &self,
363 src: &str,
364 filename: &str,
365 include_dirs: &[BnString],
366 auto_type_source: &str,
367 ) -> Result<TypeParserResult, TypeParserError> {
368 let source_cstr = BnString::new(src);
369 let file_name_cstr = BnString::new(filename);
370 let auto_type_source = BnString::new(auto_type_source);
371
372 let mut raw_result = BNTypeParserResult::default();
373 let mut error_string = ptr::null_mut();
374 let success = unsafe {
375 BNParseTypesFromSource(
376 self.handle,
377 source_cstr.as_ptr(),
378 file_name_cstr.as_ptr(),
379 &mut raw_result,
380 &mut error_string,
381 include_dirs.as_ptr() as *mut *const ffi::c_char,
382 include_dirs.len(),
383 auto_type_source.as_ptr(),
384 )
385 };
386
387 if success {
388 let result = TypeParserResult::from_raw(&raw_result);
389 TypeParserResult::free_raw(raw_result);
391 Ok(result)
392 } else {
393 assert!(!error_string.is_null());
394 Err(TypeParserError::new(
395 TypeParserErrorSeverity::FatalSeverity,
396 unsafe { BnString::into_string(error_string) },
397 filename.to_string(),
398 0,
399 0,
400 ))
401 }
402 }
403
404 pub fn parse_types_from_source_file(
406 &self,
407 filename: &str,
408 include_dirs: &[BnString],
409 auto_type_source: &str,
410 ) -> Result<TypeParserResult, TypeParserError> {
411 let file_name_cstr = BnString::new(filename);
412 let auto_type_source = BnString::new(auto_type_source);
413
414 let mut raw_result = BNTypeParserResult::default();
415 let mut error_string = ptr::null_mut();
416 let success = unsafe {
417 BNParseTypesFromSourceFile(
418 self.handle,
419 file_name_cstr.as_ptr(),
420 &mut raw_result,
421 &mut error_string,
422 include_dirs.as_ptr() as *mut *const ffi::c_char,
423 include_dirs.len(),
424 auto_type_source.as_ptr(),
425 )
426 };
427
428 if success {
429 let result = TypeParserResult::from_raw(&raw_result);
430 TypeParserResult::free_raw(raw_result);
432 Ok(result)
433 } else {
434 assert!(!error_string.is_null());
435 Err(TypeParserError::new(
436 TypeParserErrorSeverity::FatalSeverity,
437 unsafe { BnString::into_string(error_string) },
438 filename.to_string(),
439 0,
440 0,
441 ))
442 }
443 }
444}
445
446impl Debug for Platform {
447 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
448 f.debug_struct("Platform")
449 .field("name", &self.name())
450 .field("arch", &self.arch().name())
451 .finish()
452 }
453}
454
455impl ToOwned for Platform {
456 type Owned = Ref<Self>;
457
458 fn to_owned(&self) -> Self::Owned {
459 unsafe { RefCountable::inc_ref(self) }
460 }
461}
462
463unsafe impl RefCountable for Platform {
464 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
465 Ref::new(Self {
466 handle: BNNewPlatformReference(handle.handle),
467 })
468 }
469
470 unsafe fn dec_ref(handle: &Self) {
471 BNFreePlatform(handle.handle);
472 }
473}
474
475impl CoreArrayProvider for Platform {
476 type Raw = *mut BNPlatform;
477 type Context = ();
478 type Wrapped<'a> = Guard<'a, Platform>;
479}
480
481unsafe impl CoreArrayProviderInner for Platform {
482 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
483 BNFreePlatformList(raw, count);
484 }
485
486 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
487 debug_assert!(!raw.is_null());
488 Guard::new(Self::from_raw(*raw), context)
489 }
490}