summaryrefslogtreecommitdiff
path: root/rust/src/platform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/platform.rs')
-rw-r--r--rust/src/platform.rs271
1 files changed, 162 insertions, 109 deletions
diff --git a/rust/src/platform.rs b/rust/src/platform.rs
index 4e31a0a2..62c61297 100644
--- a/rust/src/platform.rs
+++ b/rust/src/platform.rs
@@ -14,18 +14,20 @@
//! Contains all information related to the execution environment of the binary, mainly the calling conventions used
-use std::{borrow::Borrow, collections::HashMap, os::raw, path::Path, ptr, slice};
-
-use binaryninjacore_sys::*;
-
+use crate::type_container::TypeContainer;
+use crate::type_parser::{TypeParserError, TypeParserErrorSeverity, TypeParserResult};
use crate::{
architecture::{Architecture, CoreArchitecture},
- callingconvention::CallingConvention,
+ calling_convention::CoreCallingConvention,
rc::*,
string::*,
- typelibrary::TypeLibrary,
- types::{QualifiedName, QualifiedNameAndType, Type},
+ type_library::TypeLibrary,
+ types::QualifiedNameAndType,
};
+use binaryninjacore_sys::*;
+use std::fmt::Debug;
+use std::ptr::NonNull;
+use std::{borrow::Borrow, ffi, ptr};
#[derive(PartialEq, Eq, Hash)]
pub struct Platform {
@@ -37,7 +39,7 @@ unsafe impl Sync for Platform {}
macro_rules! cc_func {
($get_name:ident, $get_api:ident, $set_name:ident, $set_api:ident) => {
- pub fn $get_name(&self) -> Option<Ref<CallingConvention<CoreArchitecture>>> {
+ pub fn $get_name(&self) -> Option<Ref<CoreCallingConvention>> {
let arch = self.arch();
unsafe {
@@ -46,16 +48,19 @@ macro_rules! cc_func {
if cc.is_null() {
None
} else {
- Some(CallingConvention::ref_from_raw(cc, arch))
+ Some(CoreCallingConvention::ref_from_raw(
+ cc,
+ arch.as_ref().handle(),
+ ))
}
}
}
- pub fn $set_name<A: Architecture>(&self, cc: &CallingConvention<A>) {
+ pub fn $set_name(&self, cc: &CoreCallingConvention) {
let arch = self.arch();
assert!(
- cc.arch_handle.borrow().as_ref().0 == arch.0,
+ cc.arch_handle.borrow().as_ref().handle == arch.handle,
"use of calling convention with non-matching Platform architecture!"
);
@@ -67,9 +72,13 @@ macro_rules! cc_func {
}
impl Platform {
- pub(crate) unsafe fn ref_from_raw(handle: *mut BNPlatform) -> Ref<Self> {
+ pub(crate) unsafe fn from_raw(handle: *mut BNPlatform) -> Self {
debug_assert!(!handle.is_null());
+ Self { handle }
+ }
+ pub(crate) unsafe fn ref_from_raw(handle: *mut BNPlatform) -> Ref<Self> {
+ debug_assert!(!handle.is_null());
Ref::new(Self { handle })
}
@@ -98,7 +107,7 @@ impl Platform {
pub fn list_by_arch(arch: &CoreArchitecture) -> Array<Platform> {
unsafe {
let mut count = 0;
- let handles = BNGetPlatformListByArchitecture(arch.0, &mut count);
+ let handles = BNGetPlatformListByArchitecture(arch.handle, &mut count);
Array::new(handles, count, ())
}
@@ -125,7 +134,7 @@ impl Platform {
let mut count = 0;
let handles = BNGetPlatformListByOSAndArchitecture(
raw_name.as_ref().as_ptr() as *mut _,
- arch.0,
+ arch.handle,
&mut count,
);
@@ -145,10 +154,8 @@ impl Platform {
pub fn new<A: Architecture, S: BnStrCompatible>(arch: &A, name: S) -> Ref<Self> {
let name = name.into_bytes_with_nul();
unsafe {
- let handle = BNCreatePlatform(arch.as_ref().0, name.as_ref().as_ptr() as *mut _);
-
+ let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ref().as_ptr() as *mut _);
assert!(!handle.is_null());
-
Ref::new(Self { handle })
}
}
@@ -164,10 +171,23 @@ impl Platform {
unsafe { CoreArchitecture::from_raw(BNGetPlatformArchitecture(self.handle)) }
}
- pub fn get_type_libraries_by_name(&self, name: &QualifiedName) -> Array<TypeLibrary> {
+ pub fn type_container(&self) -> TypeContainer {
+ let type_container_ptr = NonNull::new(unsafe { BNGetPlatformTypeContainer(self.handle) });
+ // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
+ // TODO: We are cloning here for platforms but we dont need to do this for [BinaryViewExt::type_container]
+ // TODO: Why does this require that we, construct a TypeContainer, duplicate the type container, then drop the original.
+ unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()).clone() }
+ }
+
+ pub fn get_type_libraries_by_name<T: BnStrCompatible>(&self, name: T) -> Array<TypeLibrary> {
let mut count = 0;
+ let name = name.into_bytes_with_nul();
let result = unsafe {
- BNGetPlatformTypeLibrariesByName(self.handle, &name.0 as *const _ as *mut _, &mut count)
+ BNGetPlatformTypeLibrariesByName(
+ self.handle,
+ name.as_ref().as_ptr() as *mut _,
+ &mut count,
+ )
};
assert!(!result.is_null());
unsafe { Array::new(result, count, ()) }
@@ -216,11 +236,10 @@ impl Platform {
BNSetPlatformSystemCallConvention
);
- pub fn calling_conventions(&self) -> Array<CallingConvention<CoreArchitecture>> {
+ pub fn calling_conventions(&self) -> Array<CoreCallingConvention> {
unsafe {
let mut count = 0;
let handles = BNGetPlatformCallingConventions(self.handle, &mut count);
-
Array::new(handles, count, self.arch())
}
}
@@ -229,7 +248,6 @@ impl Platform {
unsafe {
let mut count = 0;
let handles = BNGetPlatformTypes(self.handle, &mut count);
-
Array::new(handles, count, ())
}
}
@@ -238,7 +256,6 @@ impl Platform {
unsafe {
let mut count = 0;
let handles = BNGetPlatformVariables(self.handle, &mut count);
-
Array::new(handles, count, ())
}
}
@@ -247,108 +264,143 @@ impl Platform {
unsafe {
let mut count = 0;
let handles = BNGetPlatformFunctions(self.handle, &mut count);
-
Array::new(handles, count, ())
}
}
-}
-
-pub trait TypeParser {
- fn parse_types_from_source<S: BnStrCompatible, P: AsRef<Path>>(
- &self,
- _source: S,
- _filename: S,
- _include_directories: &[P],
- _auto_type_source: S,
- ) -> Result<TypeParserResult, String> {
- Err(String::new())
- }
-}
-#[derive(Clone, Default)]
-pub struct TypeParserResult {
- pub types: HashMap<String, Ref<Type>>,
- pub variables: HashMap<String, Ref<Type>>,
- pub functions: HashMap<String, Ref<Type>>,
-}
+ // TODO: system_calls
+ // TODO: add a helper function to define a system call (platform function with a specific type)
-impl TypeParser for Platform {
- fn parse_types_from_source<S: BnStrCompatible, P: AsRef<Path>>(
+ // TODO: Documentation, specifically how this differs from the TypeParser impl
+ pub fn preprocess_source(
&self,
- source: S,
- filename: S,
- include_directories: &[P],
- auto_type_source: S,
- ) -> Result<TypeParserResult, String> {
- let mut result = BNTypeParserResult {
- functionCount: 0,
- typeCount: 0,
- variableCount: 0,
- functions: ptr::null_mut(),
- types: ptr::null_mut(),
- variables: ptr::null_mut(),
- };
-
- let mut type_parser_result = TypeParserResult::default();
-
- let mut error_string: *mut raw::c_char = ptr::null_mut();
+ source: &str,
+ file_name: &str,
+ include_dirs: &[BnString],
+ ) -> Result<BnString, TypeParserError> {
+ let source_cstr = BnString::new(source);
+ let file_name_cstr = BnString::new(file_name);
- let src = source.into_bytes_with_nul();
- let filename = filename.into_bytes_with_nul();
- let auto_type_source = auto_type_source.into_bytes_with_nul();
-
- let mut include_dirs = vec![];
+ let mut result = ptr::null_mut();
+ let mut error_string = ptr::null_mut();
+ let success = unsafe {
+ BNPreprocessSource(
+ source_cstr.as_ptr(),
+ file_name_cstr.as_ptr(),
+ &mut result,
+ &mut error_string,
+ include_dirs.as_ptr() as *mut *const ffi::c_char,
+ include_dirs.len(),
+ )
+ };
- for dir in include_directories.iter() {
- let d = dir
- .as_ref()
- .to_string_lossy()
- .to_string()
- .into_bytes_with_nul();
- include_dirs.push(d.as_ptr() as _);
+ if success {
+ assert!(!result.is_null());
+ Ok(unsafe { BnString::from_raw(result) })
+ } else {
+ assert!(!error_string.is_null());
+ Err(TypeParserError::new(
+ TypeParserErrorSeverity::FatalSeverity,
+ unsafe { BnString::from_raw(error_string) }.to_string(),
+ file_name.to_string(),
+ 0,
+ 0,
+ ))
}
+ }
- unsafe {
- let success = BNParseTypesFromSource(
+ // TODO: Documentation, specifically how this differs from the TypeParser impl
+ pub fn parse_types_from_source(
+ &self,
+ src: &str,
+ filename: &str,
+ include_dirs: &[BnString],
+ auto_type_source: &str,
+ ) -> Result<TypeParserResult, TypeParserError> {
+ let source_cstr = BnString::new(src);
+ let file_name_cstr = BnString::new(filename);
+ let auto_type_source = BnString::new(auto_type_source);
+
+ let mut raw_result = BNTypeParserResult::default();
+ let mut error_string = ptr::null_mut();
+ let success = unsafe {
+ BNParseTypesFromSource(
self.handle,
- src.as_ref().as_ptr() as _,
- filename.as_ref().as_ptr() as _,
- &mut result,
+ source_cstr.as_ptr(),
+ file_name_cstr.as_ptr(),
+ &mut raw_result,
&mut error_string,
- include_dirs.as_mut_ptr(),
+ include_dirs.as_ptr() as *mut *const ffi::c_char,
include_dirs.len(),
- auto_type_source.as_ref().as_ptr() as _,
- );
-
- let error_msg = BnString::from_raw(error_string);
+ auto_type_source.as_ptr(),
+ )
+ };
- if !success {
- return Err(error_msg.to_string());
- }
+ if success {
+ let result = TypeParserResult::from_raw(&raw_result);
+ // NOTE: This is safe because the core allocated the TypeParserResult
+ TypeParserResult::free_raw(raw_result);
+ Ok(result)
+ } else {
+ assert!(!error_string.is_null());
+ Err(TypeParserError::new(
+ TypeParserErrorSeverity::FatalSeverity,
+ unsafe { BnString::from_raw(error_string) }.to_string(),
+ filename.to_string(),
+ 0,
+ 0,
+ ))
+ }
+ }
- for i in slice::from_raw_parts(result.types, result.typeCount) {
- let name = QualifiedName(i.name);
- type_parser_result
- .types
- .insert(name.string(), Type::ref_from_raw(i.type_));
- }
+ // TODO: Documentation, specifically how this differs from the TypeParser impl
+ pub fn parse_types_from_source_file(
+ &self,
+ filename: &str,
+ include_dirs: &[BnString],
+ auto_type_source: &str,
+ ) -> Result<TypeParserResult, TypeParserError> {
+ let file_name_cstr = BnString::new(filename);
+ let auto_type_source = BnString::new(auto_type_source);
- for i in slice::from_raw_parts(result.functions, result.functionCount) {
- let name = QualifiedName(i.name);
- type_parser_result
- .functions
- .insert(name.string(), Type::ref_from_raw(i.type_));
- }
+ let mut raw_result = BNTypeParserResult::default();
+ let mut error_string = ptr::null_mut();
+ let success = unsafe {
+ BNParseTypesFromSourceFile(
+ self.handle,
+ file_name_cstr.as_ptr(),
+ &mut raw_result,
+ &mut error_string,
+ include_dirs.as_ptr() as *mut *const ffi::c_char,
+ include_dirs.len(),
+ auto_type_source.as_ptr(),
+ )
+ };
- for i in slice::from_raw_parts(result.variables, result.variableCount) {
- let name = QualifiedName(i.name);
- type_parser_result
- .variables
- .insert(name.string(), Type::ref_from_raw(i.type_));
- }
+ if success {
+ let result = TypeParserResult::from_raw(&raw_result);
+ // NOTE: This is safe because the core allocated the TypeParserResult
+ TypeParserResult::free_raw(raw_result);
+ Ok(result)
+ } else {
+ assert!(!error_string.is_null());
+ Err(TypeParserError::new(
+ TypeParserErrorSeverity::FatalSeverity,
+ unsafe { BnString::from_raw(error_string) }.to_string(),
+ filename.to_string(),
+ 0,
+ 0,
+ ))
}
+ }
+}
- Ok(type_parser_result)
+impl Debug for Platform {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Platform")
+ .field("name", &self.name())
+ .field("arch", &self.arch())
+ .finish()
}
}
@@ -379,11 +431,12 @@ impl CoreArrayProvider for Platform {
}
unsafe impl CoreArrayProviderInner for Platform {
- unsafe fn free(raw: *mut *mut BNPlatform, count: usize, _context: &()) {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreePlatformList(raw, count);
}
- unsafe fn wrap_raw<'a>(raw: &'a *mut BNPlatform, context: &'a ()) -> Self::Wrapped<'a> {
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
debug_assert!(!raw.is_null());
- Guard::new(Platform { handle: *raw }, context)
+ Guard::new(Self::from_raw(*raw), context)
}
}