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 calling_conventions(&self) -> Array<CoreCallingConvention> {
251 unsafe {
252 let mut count = 0;
253 let handles = BNGetPlatformCallingConventions(self.handle, &mut count);
254 Array::new(handles, count, self.arch())
255 }
256 }
257
258 pub fn types(&self) -> Array<QualifiedNameAndType> {
259 unsafe {
260 let mut count = 0;
261 let handles = BNGetPlatformTypes(self.handle, &mut count);
262 Array::new(handles, count, ())
263 }
264 }
265
266 pub fn variables(&self) -> Array<QualifiedNameAndType> {
267 unsafe {
268 let mut count = 0;
269 let handles = BNGetPlatformVariables(self.handle, &mut count);
270 Array::new(handles, count, ())
271 }
272 }
273
274 pub fn functions(&self) -> Array<QualifiedNameAndType> {
275 unsafe {
276 let mut count = 0;
277 let handles = BNGetPlatformFunctions(self.handle, &mut count);
278 Array::new(handles, count, ())
279 }
280 }
281
282 pub fn function_by_name<T: Into<QualifiedName>>(
283 &self,
284 name: T,
285 exact_match: bool,
286 ) -> Option<Ref<Type>> {
287 let mut raw_name = QualifiedName::into_raw(name.into());
288 unsafe {
289 let type_handle = BNGetPlatformFunctionByName(self.handle, &mut raw_name, exact_match);
290 QualifiedName::free_raw(raw_name);
291 if type_handle.is_null() {
292 return None;
293 }
294 Some(Type::ref_from_raw(type_handle))
295 }
296 }
297
298 pub fn preprocess_source(
303 &self,
304 source: &str,
305 file_name: &str,
306 include_dirs: &[BnString],
307 ) -> Result<BnString, TypeParserError> {
308 let source_cstr = BnString::new(source);
309 let file_name_cstr = BnString::new(file_name);
310
311 let mut result = ptr::null_mut();
312 let mut error_string = ptr::null_mut();
313 let success = unsafe {
314 BNPreprocessSource(
315 source_cstr.as_ptr(),
316 file_name_cstr.as_ptr(),
317 &mut result,
318 &mut error_string,
319 include_dirs.as_ptr() as *mut *const ffi::c_char,
320 include_dirs.len(),
321 )
322 };
323
324 if success {
325 assert!(!result.is_null());
326 Ok(unsafe { BnString::from_raw(result) })
327 } else {
328 assert!(!error_string.is_null());
329 Err(TypeParserError::new(
330 TypeParserErrorSeverity::FatalSeverity,
331 unsafe { BnString::into_string(error_string) },
332 file_name.to_string(),
333 0,
334 0,
335 ))
336 }
337 }
338
339 pub fn parse_types_from_source(
341 &self,
342 src: &str,
343 filename: &str,
344 include_dirs: &[BnString],
345 auto_type_source: &str,
346 ) -> Result<TypeParserResult, TypeParserError> {
347 let source_cstr = BnString::new(src);
348 let file_name_cstr = BnString::new(filename);
349 let auto_type_source = BnString::new(auto_type_source);
350
351 let mut raw_result = BNTypeParserResult::default();
352 let mut error_string = ptr::null_mut();
353 let success = unsafe {
354 BNParseTypesFromSource(
355 self.handle,
356 source_cstr.as_ptr(),
357 file_name_cstr.as_ptr(),
358 &mut raw_result,
359 &mut error_string,
360 include_dirs.as_ptr() as *mut *const ffi::c_char,
361 include_dirs.len(),
362 auto_type_source.as_ptr(),
363 )
364 };
365
366 if success {
367 let result = TypeParserResult::from_raw(&raw_result);
368 TypeParserResult::free_raw(raw_result);
370 Ok(result)
371 } else {
372 assert!(!error_string.is_null());
373 Err(TypeParserError::new(
374 TypeParserErrorSeverity::FatalSeverity,
375 unsafe { BnString::into_string(error_string) },
376 filename.to_string(),
377 0,
378 0,
379 ))
380 }
381 }
382
383 pub fn parse_types_from_source_file(
385 &self,
386 filename: &str,
387 include_dirs: &[BnString],
388 auto_type_source: &str,
389 ) -> Result<TypeParserResult, TypeParserError> {
390 let file_name_cstr = BnString::new(filename);
391 let auto_type_source = BnString::new(auto_type_source);
392
393 let mut raw_result = BNTypeParserResult::default();
394 let mut error_string = ptr::null_mut();
395 let success = unsafe {
396 BNParseTypesFromSourceFile(
397 self.handle,
398 file_name_cstr.as_ptr(),
399 &mut raw_result,
400 &mut error_string,
401 include_dirs.as_ptr() as *mut *const ffi::c_char,
402 include_dirs.len(),
403 auto_type_source.as_ptr(),
404 )
405 };
406
407 if success {
408 let result = TypeParserResult::from_raw(&raw_result);
409 TypeParserResult::free_raw(raw_result);
411 Ok(result)
412 } else {
413 assert!(!error_string.is_null());
414 Err(TypeParserError::new(
415 TypeParserErrorSeverity::FatalSeverity,
416 unsafe { BnString::into_string(error_string) },
417 filename.to_string(),
418 0,
419 0,
420 ))
421 }
422 }
423}
424
425impl Debug for Platform {
426 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427 f.debug_struct("Platform")
428 .field("name", &self.name())
429 .field("arch", &self.arch().name())
430 .finish()
431 }
432}
433
434impl ToOwned for Platform {
435 type Owned = Ref<Self>;
436
437 fn to_owned(&self) -> Self::Owned {
438 unsafe { RefCountable::inc_ref(self) }
439 }
440}
441
442unsafe impl RefCountable for Platform {
443 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
444 Ref::new(Self {
445 handle: BNNewPlatformReference(handle.handle),
446 })
447 }
448
449 unsafe fn dec_ref(handle: &Self) {
450 BNFreePlatform(handle.handle);
451 }
452}
453
454impl CoreArrayProvider for Platform {
455 type Raw = *mut BNPlatform;
456 type Context = ();
457 type Wrapped<'a> = Guard<'a, Platform>;
458}
459
460unsafe impl CoreArrayProviderInner for Platform {
461 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
462 BNFreePlatformList(raw, count);
463 }
464
465 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
466 debug_assert!(!raw.is_null());
467 Guard::new(Self::from_raw(*raw), context)
468 }
469}