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)]
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 preprocess_source(
287 &self,
288 source: &str,
289 file_name: &str,
290 include_dirs: &[BnString],
291 ) -> Result<BnString, TypeParserError> {
292 let source_cstr = BnString::new(source);
293 let file_name_cstr = BnString::new(file_name);
294
295 let mut result = ptr::null_mut();
296 let mut error_string = ptr::null_mut();
297 let success = unsafe {
298 BNPreprocessSource(
299 source_cstr.as_ptr(),
300 file_name_cstr.as_ptr(),
301 &mut result,
302 &mut error_string,
303 include_dirs.as_ptr() as *mut *const ffi::c_char,
304 include_dirs.len(),
305 )
306 };
307
308 if success {
309 assert!(!result.is_null());
310 Ok(unsafe { BnString::from_raw(result) })
311 } else {
312 assert!(!error_string.is_null());
313 Err(TypeParserError::new(
314 TypeParserErrorSeverity::FatalSeverity,
315 unsafe { BnString::into_string(error_string) },
316 file_name.to_string(),
317 0,
318 0,
319 ))
320 }
321 }
322
323 pub fn parse_types_from_source(
325 &self,
326 src: &str,
327 filename: &str,
328 include_dirs: &[BnString],
329 auto_type_source: &str,
330 ) -> Result<TypeParserResult, TypeParserError> {
331 let source_cstr = BnString::new(src);
332 let file_name_cstr = BnString::new(filename);
333 let auto_type_source = BnString::new(auto_type_source);
334
335 let mut raw_result = BNTypeParserResult::default();
336 let mut error_string = ptr::null_mut();
337 let success = unsafe {
338 BNParseTypesFromSource(
339 self.handle,
340 source_cstr.as_ptr(),
341 file_name_cstr.as_ptr(),
342 &mut raw_result,
343 &mut error_string,
344 include_dirs.as_ptr() as *mut *const ffi::c_char,
345 include_dirs.len(),
346 auto_type_source.as_ptr(),
347 )
348 };
349
350 if success {
351 let result = TypeParserResult::from_raw(&raw_result);
352 TypeParserResult::free_raw(raw_result);
354 Ok(result)
355 } else {
356 assert!(!error_string.is_null());
357 Err(TypeParserError::new(
358 TypeParserErrorSeverity::FatalSeverity,
359 unsafe { BnString::into_string(error_string) },
360 filename.to_string(),
361 0,
362 0,
363 ))
364 }
365 }
366
367 pub fn parse_types_from_source_file(
369 &self,
370 filename: &str,
371 include_dirs: &[BnString],
372 auto_type_source: &str,
373 ) -> Result<TypeParserResult, TypeParserError> {
374 let file_name_cstr = BnString::new(filename);
375 let auto_type_source = BnString::new(auto_type_source);
376
377 let mut raw_result = BNTypeParserResult::default();
378 let mut error_string = ptr::null_mut();
379 let success = unsafe {
380 BNParseTypesFromSourceFile(
381 self.handle,
382 file_name_cstr.as_ptr(),
383 &mut raw_result,
384 &mut error_string,
385 include_dirs.as_ptr() as *mut *const ffi::c_char,
386 include_dirs.len(),
387 auto_type_source.as_ptr(),
388 )
389 };
390
391 if success {
392 let result = TypeParserResult::from_raw(&raw_result);
393 TypeParserResult::free_raw(raw_result);
395 Ok(result)
396 } else {
397 assert!(!error_string.is_null());
398 Err(TypeParserError::new(
399 TypeParserErrorSeverity::FatalSeverity,
400 unsafe { BnString::into_string(error_string) },
401 filename.to_string(),
402 0,
403 0,
404 ))
405 }
406 }
407}
408
409impl Debug for Platform {
410 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411 f.debug_struct("Platform")
412 .field("name", &self.name())
413 .field("arch", &self.arch().name())
414 .finish()
415 }
416}
417
418impl ToOwned for Platform {
419 type Owned = Ref<Self>;
420
421 fn to_owned(&self) -> Self::Owned {
422 unsafe { RefCountable::inc_ref(self) }
423 }
424}
425
426unsafe impl RefCountable for Platform {
427 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
428 Ref::new(Self {
429 handle: BNNewPlatformReference(handle.handle),
430 })
431 }
432
433 unsafe fn dec_ref(handle: &Self) {
434 BNFreePlatform(handle.handle);
435 }
436}
437
438impl CoreArrayProvider for Platform {
439 type Raw = *mut BNPlatform;
440 type Context = ();
441 type Wrapped<'a> = Guard<'a, Platform>;
442}
443
444unsafe impl CoreArrayProviderInner for Platform {
445 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
446 BNFreePlatformList(raw, count);
447 }
448
449 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
450 debug_assert!(!raw.is_null());
451 Guard::new(Self::from_raw(*raw), context)
452 }
453}