Skip to content

Commit

Permalink
More rust cleanup
Browse files Browse the repository at this point in the history
- Hopefully fixed the rust.yml CI
- Added TypePrinter API (this is still WIP and will crash)
- Added TypeParser API
- Added TypeContainer API
- More work around QualifiedName apis
  • Loading branch information
emesare committed Jan 10, 2025
1 parent 9131cb5 commit 44a1415
Show file tree
Hide file tree
Showing 16 changed files with 2,098 additions and 1,762 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Ensure rustfmt is installed and setup problem matcher
# Ensure rustfmt is installed
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt
- name: Rustfmt Check
working-directory: ./rust
uses: actions-rust-lang/rustfmt@v1
with:
manifest-path: ./rust
8 changes: 4 additions & 4 deletions plugins/pdb-ng/src/type_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
ClassKind::Interface => NamedTypeReferenceClass::StructNamedTypeClass,
};
return Ok(Some(Box::new(ParsedType::Bare(Type::named_type(
&*NamedTypeReference::new(ntr_class, QualifiedName::from(class_name)),
&*NamedTypeReference::new(ntr_class, class_name),
)))));
}

Expand Down Expand Up @@ -1083,7 +1083,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
NamedTypeReferenceClass::StructNamedTypeClass
};
vt_bases.push(BaseStructure::new(
NamedTypeReference::new(ntr_class, vt_base_name.into()),
NamedTypeReference::new(ntr_class, vt_base_name),
0,
vt_base_type.width(),
));
Expand Down Expand Up @@ -1638,7 +1638,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {

let ntr_class = NamedTypeReferenceClass::EnumNamedTypeClass;
return Ok(Some(Box::new(ParsedType::Bare(Type::named_type(
&*NamedTypeReference::new(ntr_class, QualifiedName::from(enum_name)),
&*NamedTypeReference::new(ntr_class, enum_name),
)))));
}

Expand Down Expand Up @@ -1766,7 +1766,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {

let ntr_class = NamedTypeReferenceClass::UnionNamedTypeClass;
return Ok(Some(Box::new(ParsedType::Bare(Type::named_type(
&*NamedTypeReference::new(ntr_class, QualifiedName::from(union_name)),
&*NamedTypeReference::new(ntr_class, union_name),
)))));
}

Expand Down
10 changes: 5 additions & 5 deletions plugins/warp/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,11 +434,11 @@ pub fn to_bn_type<A: BNArchitecture>(arch: &A, ty: &Type) -> BNRef<BNType> {
Some(guid) => BNNamedTypeReference::new_with_id(
NamedTypeReferenceClass::UnknownNamedTypeClass,
guid.to_string(),
base_struct_ntr_name.into(),
base_struct_ntr_name,
),
None => BNNamedTypeReference::new(
NamedTypeReferenceClass::UnknownNamedTypeClass,
base_struct_ntr_name.into(),
base_struct_ntr_name,
),
};
base_structs.push(BNBaseStructure::new(
Expand Down Expand Up @@ -548,19 +548,19 @@ pub fn to_bn_type<A: BNArchitecture>(arch: &A, ty: &Type) -> BNRef<BNType> {
NamedTypeReference::new_with_id(
NamedTypeReferenceClass::UnknownNamedTypeClass,
guid_str,
ntr_name.into(),
ntr_name,
)
}
None => match c.name.as_ref() {
Some(ntr_name) => NamedTypeReference::new(
NamedTypeReferenceClass::UnknownNamedTypeClass,
ntr_name.into(),
ntr_name,
),
None => {
log::error!("Referrer with no reference! {:?}", c);
NamedTypeReference::new(
NamedTypeReferenceClass::UnknownNamedTypeClass,
"AHHHHHH".into(),
"AHHHHHH",
)
}
},
Expand Down
29 changes: 29 additions & 0 deletions rust/src/binaryview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use std::{ops, result, slice};
use crate::rc::*;
use crate::references::{CodeReference, DataReference};
use crate::string::*;
use crate::typecontainer::TypeContainer;
use crate::variable::DataVariable;
// TODO : general reorg of modules related to bv

Expand Down Expand Up @@ -1474,6 +1475,34 @@ pub trait BinaryViewExt: BinaryViewBase {
unsafe { Array::new(result, count, ()) }
}

/// Type container for all types (user and auto) in the Binary View.
///
/// NOTE: Modifying an auto type will promote it to a user type.
fn type_container(&self) -> TypeContainer {
let type_container_ptr =
NonNull::new(unsafe { BNGetAnalysisTypeContainer(self.as_ref().handle) });
// NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
}

/// Type container for user types in the Binary View.
fn user_type_container(&self) -> TypeContainer {
let type_container_ptr =
NonNull::new(unsafe { BNGetAnalysisUserTypeContainer(self.as_ref().handle) });
// NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
}

/// Type container for auto types in the Binary View.
///
/// NOTE: Unlike [`Self::type_container`] modification of auto types will **NOT** promote it to a user type.
fn auto_type_container(&self) -> TypeContainer {
let type_container_ptr =
NonNull::new(unsafe { BNGetAnalysisAutoTypeContainer(self.as_ref().handle) });
// NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
}

/// Make the contents of a type library available for type/import resolution
fn add_type_library(&self, library: &TypeLibrary) {
unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) }
Expand Down
4 changes: 3 additions & 1 deletion rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ pub mod fileaccessor;
pub mod filemetadata;
pub mod flowgraph;
pub mod function;
pub mod typeparser;
pub mod functionrecognizer;
pub mod headless;
pub mod hlil;
Expand All @@ -172,7 +171,10 @@ pub mod symbol;
pub mod tags;
pub mod templatesimplifier;
pub mod typearchive;
pub mod typecontainer;
pub mod typelibrary;
pub mod typeparser;
pub mod typeprinter;
pub mod types;
pub mod update;
pub mod variable;
Expand Down
43 changes: 28 additions & 15 deletions rust/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@

//! Contains all information related to the execution environment of the binary, mainly the calling conventions used
use std::{borrow::Borrow, ffi, ptr};

use binaryninjacore_sys::*;
use std::ptr::NonNull;
use std::{borrow::Borrow, ffi, ptr};

use crate::typecontainer::TypeContainer;
use crate::typeparser::{TypeParserError, TypeParserErrorSeverity, TypeParserResult};
use crate::{
architecture::{Architecture, CoreArchitecture},
callingconvention::CallingConvention,
rc::*,
string::*,
typelibrary::TypeLibrary,
types::{QualifiedName, QualifiedNameAndType, Type},
types::QualifiedNameAndType,
};
use crate::typeparser::{TypeParserError, TypeParserErrorSeverity, TypeParserResult};

#[derive(PartialEq, Eq, Hash)]
pub struct Platform {
Expand Down Expand Up @@ -169,6 +170,14 @@ impl Platform {
unsafe { CoreArchitecture::from_raw(BNGetPlatformArchitecture(self.handle)) }
}

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();
Expand Down Expand Up @@ -262,6 +271,7 @@ impl Platform {
}
}

// TODO: Documentation, specifically how this differs from the TypeParser impl
pub fn preprocess_source(
&self,
source: &str,
Expand All @@ -283,21 +293,23 @@ impl Platform {
include_dirs.len(),
)
};

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) },
file_name,
unsafe { BnString::from_raw(error_string) }.to_string(),
file_name.to_string(),
0,
0,
))
}
}

// TODO: Documentation, specifically how this differs from the TypeParser impl
pub fn parse_types_from_source(
&self,
src: &str,
Expand All @@ -309,14 +321,14 @@ impl Platform {
let file_name_cstr = BnString::new(filename);
let auto_type_source = BnString::new(auto_type_source);

let mut result = BNTypeParserResult::default();
let mut raw_result = BNTypeParserResult::default();
let mut error_string = ptr::null_mut();
let success = unsafe {
BNParseTypesFromSource(
self.handle,
source_cstr.as_ptr(),
file_name_cstr.as_ptr(),
&mut result,
&mut raw_result,
&mut error_string,
include_dirs.as_ptr() as *mut *const ffi::c_char,
include_dirs.len(),
Expand All @@ -325,19 +337,20 @@ impl Platform {
};

if success {
Ok(unsafe { TypeParserResult::from_raw(result) })
Ok(raw_result.into())
} else {
assert!(!error_string.is_null());
Err(TypeParserError::new(
TypeParserErrorSeverity::FatalSeverity,
unsafe { BnString::from_raw(error_string) },
filename,
unsafe { BnString::from_raw(error_string) }.to_string(),
filename.to_string(),
0,
0,
))
}
}

// TODO: Documentation, specifically how this differs from the TypeParser impl
pub fn parse_types_from_source_file(
&self,
filename: &str,
Expand All @@ -362,13 +375,13 @@ impl Platform {
};

if success {
Ok(unsafe { TypeParserResult::from_raw(result) })
Ok(result.into())
} else {
assert!(!error_string.is_null());
Err(TypeParserError::new(
TypeParserErrorSeverity::FatalSeverity,
unsafe { BnString::from_raw(error_string) },
filename,
unsafe { BnString::from_raw(error_string) }.to_string(),
filename.to_string(),
0,
0,
))
Expand Down
36 changes: 20 additions & 16 deletions rust/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,26 +203,14 @@ pub(crate) unsafe trait CoreArrayProviderInner: CoreArrayProvider {
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a>;
}

// TODO: I would really like if we impld Debug for this, but lifetimes are hard!
#[allow(private_bounds)]
pub struct Array<P: CoreArrayProviderInner> {
contents: *mut P::Raw,
count: usize,
context: P::Context,
}

unsafe impl<P> Sync for Array<P>
where
P: CoreArrayProviderInner,
P::Context: Sync,
{
}
unsafe impl<P> Send for Array<P>
where
P: CoreArrayProviderInner,
P::Context: Send,
{
}

#[allow(private_bounds)]
impl<P: CoreArrayProviderInner> Array<P> {
pub(crate) unsafe fn new(raw: *mut P::Raw, count: usize, context: P::Context) -> Self {
Expand All @@ -242,10 +230,13 @@ impl<P: CoreArrayProviderInner> Array<P> {
pub fn is_empty(&self) -> bool {
self.count == 0
}
}

#[allow(private_bounds)]
impl<P: CoreArrayProviderInner> Array<P> {
pub fn to_vec(&self) -> Vec<P::Wrapped<'_>> {
let mut res = Vec::with_capacity(self.count);
res.extend(self.iter());
res
}

#[inline]
pub fn get(&self, index: usize) -> P::Wrapped<'_> {
unsafe {
Expand All @@ -262,6 +253,19 @@ impl<P: CoreArrayProviderInner> Array<P> {
}
}

unsafe impl<P> Sync for Array<P>
where
P: CoreArrayProviderInner,
P::Context: Sync,
{
}
unsafe impl<P> Send for Array<P>
where
P: CoreArrayProviderInner,
P::Context: Send,
{
}

impl<'a, P: CoreArrayProviderInner> IntoIterator for &'a Array<P> {
type Item = P::Wrapped<'a>;
type IntoIter = ArrayIter<'a, P>;
Expand Down
2 changes: 1 addition & 1 deletion rust/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ unsafe impl BnStrCompatible for &Path {
type Result = Vec<u8>;

fn into_bytes_with_nul(self) -> Self::Result {
self.to_string_lossy().into_bytes_with_nul()
self.as_os_str().as_encoded_bytes().to_vec()
}
}

Expand Down
Loading

0 comments on commit 44a1415

Please sign in to comment.