1use crate::type_container::TypeContainer;
18use crate::type_parser::{TypeParserError, TypeParserErrorSeverity, TypeParserResult};
19use crate::{
20 architecture::{Architecture, CoreArchitecture},
21 calling_convention::CoreCallingConvention,
22 rc::*,
23 string::*,
24 type_library::TypeLibrary,
25 types::QualifiedNameAndType,
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 type_container(&self) -> TypeContainer {
169 let type_container_ptr = NonNull::new(unsafe { BNGetPlatformTypeContainer(self.handle) });
170 unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
174 }
175
176 pub fn get_type_libraries_by_name(&self, name: &str) -> Array<TypeLibrary> {
181 let mut count = 0;
182 let name = name.to_cstr();
183 let result =
184 unsafe { BNGetPlatformTypeLibrariesByName(self.handle, name.as_ptr(), &mut count) };
185 assert!(!result.is_null());
186 unsafe { Array::new(result, count, ()) }
187 }
188
189 pub fn get_type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> {
193 let libraries = self.get_type_libraries_by_name(name);
194 libraries
195 .iter()
196 .find(|lib| lib.name() == name)
197 .map(|lib| lib.to_owned())
198 }
199
200 pub fn register_os(&self, os: &str) {
201 let os = os.to_cstr();
202 unsafe {
203 BNRegisterPlatform(os.as_ptr(), self.handle);
204 }
205 }
206
207 cc_func!(
208 get_default_calling_convention,
209 BNGetPlatformDefaultCallingConvention,
210 set_default_calling_convention,
211 BNRegisterPlatformDefaultCallingConvention
212 );
213
214 cc_func!(
215 get_cdecl_calling_convention,
216 BNGetPlatformCdeclCallingConvention,
217 set_cdecl_calling_convention,
218 BNRegisterPlatformCdeclCallingConvention
219 );
220
221 cc_func!(
222 get_stdcall_calling_convention,
223 BNGetPlatformStdcallCallingConvention,
224 set_stdcall_calling_convention,
225 BNRegisterPlatformStdcallCallingConvention
226 );
227
228 cc_func!(
229 get_fastcall_calling_convention,
230 BNGetPlatformFastcallCallingConvention,
231 set_fastcall_calling_convention,
232 BNRegisterPlatformFastcallCallingConvention
233 );
234
235 cc_func!(
236 get_syscall_convention,
237 BNGetPlatformSystemCallConvention,
238 set_syscall_convention,
239 BNSetPlatformSystemCallConvention
240 );
241
242 pub fn calling_conventions(&self) -> Array<CoreCallingConvention> {
243 unsafe {
244 let mut count = 0;
245 let handles = BNGetPlatformCallingConventions(self.handle, &mut count);
246 Array::new(handles, count, self.arch())
247 }
248 }
249
250 pub fn types(&self) -> Array<QualifiedNameAndType> {
251 unsafe {
252 let mut count = 0;
253 let handles = BNGetPlatformTypes(self.handle, &mut count);
254 Array::new(handles, count, ())
255 }
256 }
257
258 pub fn variables(&self) -> Array<QualifiedNameAndType> {
259 unsafe {
260 let mut count = 0;
261 let handles = BNGetPlatformVariables(self.handle, &mut count);
262 Array::new(handles, count, ())
263 }
264 }
265
266 pub fn functions(&self) -> Array<QualifiedNameAndType> {
267 unsafe {
268 let mut count = 0;
269 let handles = BNGetPlatformFunctions(self.handle, &mut count);
270 Array::new(handles, count, ())
271 }
272 }
273
274 pub fn preprocess_source(
279 &self,
280 source: &str,
281 file_name: &str,
282 include_dirs: &[BnString],
283 ) -> Result<BnString, TypeParserError> {
284 let source_cstr = BnString::new(source);
285 let file_name_cstr = BnString::new(file_name);
286
287 let mut result = ptr::null_mut();
288 let mut error_string = ptr::null_mut();
289 let success = unsafe {
290 BNPreprocessSource(
291 source_cstr.as_ptr(),
292 file_name_cstr.as_ptr(),
293 &mut result,
294 &mut error_string,
295 include_dirs.as_ptr() as *mut *const ffi::c_char,
296 include_dirs.len(),
297 )
298 };
299
300 if success {
301 assert!(!result.is_null());
302 Ok(unsafe { BnString::from_raw(result) })
303 } else {
304 assert!(!error_string.is_null());
305 Err(TypeParserError::new(
306 TypeParserErrorSeverity::FatalSeverity,
307 unsafe { BnString::into_string(error_string) },
308 file_name.to_string(),
309 0,
310 0,
311 ))
312 }
313 }
314
315 pub fn parse_types_from_source(
317 &self,
318 src: &str,
319 filename: &str,
320 include_dirs: &[BnString],
321 auto_type_source: &str,
322 ) -> Result<TypeParserResult, TypeParserError> {
323 let source_cstr = BnString::new(src);
324 let file_name_cstr = BnString::new(filename);
325 let auto_type_source = BnString::new(auto_type_source);
326
327 let mut raw_result = BNTypeParserResult::default();
328 let mut error_string = ptr::null_mut();
329 let success = unsafe {
330 BNParseTypesFromSource(
331 self.handle,
332 source_cstr.as_ptr(),
333 file_name_cstr.as_ptr(),
334 &mut raw_result,
335 &mut error_string,
336 include_dirs.as_ptr() as *mut *const ffi::c_char,
337 include_dirs.len(),
338 auto_type_source.as_ptr(),
339 )
340 };
341
342 if success {
343 let result = TypeParserResult::from_raw(&raw_result);
344 TypeParserResult::free_raw(raw_result);
346 Ok(result)
347 } else {
348 assert!(!error_string.is_null());
349 Err(TypeParserError::new(
350 TypeParserErrorSeverity::FatalSeverity,
351 unsafe { BnString::into_string(error_string) },
352 filename.to_string(),
353 0,
354 0,
355 ))
356 }
357 }
358
359 pub fn parse_types_from_source_file(
361 &self,
362 filename: &str,
363 include_dirs: &[BnString],
364 auto_type_source: &str,
365 ) -> Result<TypeParserResult, TypeParserError> {
366 let file_name_cstr = BnString::new(filename);
367 let auto_type_source = BnString::new(auto_type_source);
368
369 let mut raw_result = BNTypeParserResult::default();
370 let mut error_string = ptr::null_mut();
371 let success = unsafe {
372 BNParseTypesFromSourceFile(
373 self.handle,
374 file_name_cstr.as_ptr(),
375 &mut raw_result,
376 &mut error_string,
377 include_dirs.as_ptr() as *mut *const ffi::c_char,
378 include_dirs.len(),
379 auto_type_source.as_ptr(),
380 )
381 };
382
383 if success {
384 let result = TypeParserResult::from_raw(&raw_result);
385 TypeParserResult::free_raw(raw_result);
387 Ok(result)
388 } else {
389 assert!(!error_string.is_null());
390 Err(TypeParserError::new(
391 TypeParserErrorSeverity::FatalSeverity,
392 unsafe { BnString::into_string(error_string) },
393 filename.to_string(),
394 0,
395 0,
396 ))
397 }
398 }
399}
400
401impl Debug for Platform {
402 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403 f.debug_struct("Platform")
404 .field("name", &self.name())
405 .field("arch", &self.arch().name())
406 .finish()
407 }
408}
409
410impl ToOwned for Platform {
411 type Owned = Ref<Self>;
412
413 fn to_owned(&self) -> Self::Owned {
414 unsafe { RefCountable::inc_ref(self) }
415 }
416}
417
418unsafe impl RefCountable for Platform {
419 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
420 Ref::new(Self {
421 handle: BNNewPlatformReference(handle.handle),
422 })
423 }
424
425 unsafe fn dec_ref(handle: &Self) {
426 BNFreePlatform(handle.handle);
427 }
428}
429
430impl CoreArrayProvider for Platform {
431 type Raw = *mut BNPlatform;
432 type Context = ();
433 type Wrapped<'a> = Guard<'a, Platform>;
434}
435
436unsafe impl CoreArrayProviderInner for Platform {
437 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
438 BNFreePlatformList(raw, count);
439 }
440
441 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
442 debug_assert!(!raw.is_null());
443 Guard::new(Self::from_raw(*raw), context)
444 }
445}