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