summaryrefslogtreecommitdiff
path: root/rust/src/types.rs
diff options
context:
space:
mode:
authorKyleMiles <krm504@nyu.edu>2021-01-21 18:35:20 +0000
committerKyleMiles <krm504@nyu.edu>2021-01-21 19:07:07 +0000
commit2fcacc55d5466a7d17bdc0b3ce988772aa6d0653 (patch)
tree9d0f2ba19117843575936f2b93e0b6a578a84dc8 /rust/src/types.rs
parenta0da07c5c2860a5bd69921d38e438bbc1d43912f (diff)
cargo fmt and all my changes
Diffstat (limited to 'rust/src/types.rs')
-rw-r--r--rust/src/types.rs438
1 files changed, 410 insertions, 28 deletions
diff --git a/rust/src/types.rs b/rust/src/types.rs
index 80046f87..ec31c6e9 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -1,37 +1,235 @@
-use std::mem;
-use std::slice;
+// Copyright 2021 Vector 35 Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
use binaryninjacore_sys::*;
+use std::{fmt, mem, ptr, slice};
+
+use crate::architecture::Architecture;
+use crate::string::{BnStr, BnStrCompatible, BnString};
use crate::rc::*;
+pub type ReferenceType = BNReferenceType;
+pub type TypeClass = BNTypeClass;
+pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
+
+//////////
+// Type
+
#[derive(PartialEq, Eq, Hash)]
pub struct Type {
pub(crate) handle: *mut BNType,
+ pub(crate) confidence: u8,
}
-unsafe impl Send for Type {}
-unsafe impl Sync for Type {}
-
impl Type {
pub(crate) unsafe fn from_raw(handle: *mut BNType) -> Self {
debug_assert!(!handle.is_null());
- Self { handle }
+ Self {
+ handle,
+ // TODO : Remove this field and and make Confidence<Type>
+ confidence: 255,
+ }
}
-}
-impl ToOwned for Type {
- type Owned = Ref<Self>;
+ // TODO : Implement type builders (how I did with structures)
+ // pub(crate) unsafe fn from_builder(handle: *mut BNTypeBuilder) -> Self {
+ // debug_assert!(!handle.is_null());
- fn to_owned(&self) -> Self::Owned {
- unsafe { RefCountable::inc_ref(self) }
+ // Self { handle }
+ // }
+
+ // TODO : Add this to a real doc_string:
+ // use binaryninja::types::Type;
+ // let bv = unsafe { BinaryView::from_raw(view) };
+ // let my_custom_type_1 = Type::named_int(5, false, "my_w");
+ // let my_custom_type_2 = Type::int(5, false);
+ // bv.define_user_type("int_1", &my_custom_type_1);
+ // bv.define_user_type("int_2", &my_custom_type_2);
+
+ pub fn void() -> Self {
+ unsafe { Type::from_raw(BNCreateVoidType()) }
+ }
+
+ pub fn bool() -> Self {
+ unsafe { Type::from_raw(BNCreateBoolType()) }
+ }
+
+ pub fn char() -> Self {
+ Type::int(1, true)
+ }
+
+ pub fn int(width: usize, is_signed: bool) -> Self {
+ let mut is_signed = BoolWithConfidence::new(is_signed, 0);
+ unsafe {
+ Type::from_raw(BNCreateIntegerType(
+ width,
+ &mut is_signed.0,
+ BnString::new("").as_ptr() as *mut _,
+ ))
+ }
+ }
+
+ pub fn named_int<S: BnStrCompatible>(width: usize, is_signed: bool, alt_name: S) -> Self {
+ let mut is_signed = BoolWithConfidence::new(is_signed, 0);
+ // let alt_name = BnString::new(alt_name);
+ let alt_name = alt_name.as_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data
+
+ unsafe {
+ Type::from_raw(BNCreateIntegerType(
+ width,
+ &mut is_signed.0,
+ alt_name.as_ref().as_ptr() as _,
+ ))
+ }
+ }
+
+ pub fn float(width: usize) -> Self {
+ unsafe {
+ Type::from_raw(BNCreateFloatType(
+ width,
+ BnString::new("").as_ptr() as *mut _,
+ ))
+ }
+ }
+
+ pub fn named_float<S: BnStrCompatible>(width: usize, alt_name: S) -> Self {
+ // let alt_name = BnString::new(alt_name);
+ let alt_name = alt_name.as_bytes_with_nul(); // See same line in `named_int` above
+
+ unsafe { Type::from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) }
+ }
+
+ pub fn array(t: &Type, count: u64) -> Self {
+ let mut type_conf = TypeWithConfidence::new(&t, t.confidence);
+ unsafe { Type::from_raw(BNCreateArrayType(&mut type_conf.0, count)) }
+ }
+
+ pub fn structure_type(structure_type: &mut Structure) -> Self {
+ unsafe { Type::from_raw(BNCreateStructureType(structure_type.handle())) }
+ }
+
+ // TODO : Create enumeration type and finish implementing this
+ // pub fn enumeration<A: Architecture>(
+ // arch: A,
+ // enum_type: Enumeration,
+ // width: usize,
+ // is_signed: bool,
+ // ) -> Self {
+ // unsafe { Type::from_raw(BNCreateEnumerationType(arch, enum_type, width, is_signed)) }
+ // }
+
+ pub fn named_type(type_reference: NamedTypeReference) -> Self {
+ unsafe {
+ Type::from_raw(BNFinalizeTypeBuilder(BNCreateNamedTypeReferenceBuilder(
+ type_reference.handle,
+ 0,
+ 1,
+ )))
+ }
+ }
+
+ pub fn named_type_from_type<S: BnStrCompatible>(name: S, t: &Type) -> Self {
+ let mut name = QualifiedName::from(name);
+
+ unsafe {
+ Type::from_raw(BNFinalizeTypeBuilder(
+ BNCreateNamedTypeReferenceBuilderFromTypeAndId(
+ BnString::new("").as_ptr() as *mut _,
+ &mut name.0, // BNCreateNamedTypeReferenceBuilderFromTypeAndId copy's qualified the name
+ t.handle,
+ ),
+ ))
+ }
+ }
+
+ // TODO : BNCreateFunctionType
+
+ pub fn pointer<A: Architecture>(arch: &A, t: &Type) -> Self {
+ let mut is_const = BoolWithConfidence::new(false, 0);
+ let mut is_volatile = BoolWithConfidence::new(false, 0);
+ let mut type_conf = TypeWithConfidence::new(&t, t.confidence);
+ unsafe {
+ Type::from_raw(BNCreatePointerType(
+ arch.as_ref().0,
+ &mut type_conf.0,
+ &mut is_const.0,
+ &mut is_volatile.0,
+ ReferenceType::PointerReferenceType,
+ ))
+ }
+ }
+
+ pub fn const_pointer<A: Architecture>(arch: &A, t: &Type) -> Self {
+ let mut is_const = BoolWithConfidence::new(true, 0);
+ let mut is_volatile = BoolWithConfidence::new(false, 0);
+ let mut type_conf = TypeWithConfidence::new(&t, t.confidence);
+ unsafe {
+ Type::from_raw(BNCreatePointerType(
+ arch.as_ref().0,
+ &mut type_conf.0,
+ &mut is_const.0,
+ &mut is_volatile.0,
+ ReferenceType::PointerReferenceType,
+ ))
+ }
+ }
+
+ pub fn pointer_with_options<A: Architecture>(
+ arch: &A,
+ t: &Type,
+ is_const: bool,
+ is_volatile: bool,
+ ref_type: Option<ReferenceType>,
+ ) -> Self {
+ let mut is_const = BoolWithConfidence::new(is_const, 0);
+ let mut is_volatile = BoolWithConfidence::new(is_volatile, 0);
+ let mut type_conf = TypeWithConfidence::new(&t, t.confidence);
+ unsafe {
+ Type::from_raw(BNCreatePointerType(
+ arch.as_ref().0,
+ &mut type_conf.0,
+ &mut is_const.0,
+ &mut is_volatile.0,
+ ref_type.unwrap_or_else(|| ReferenceType::PointerReferenceType),
+ ))
+ }
+ }
+
+ pub fn generate_auto_demangled_type_id<'a, S: BnStrCompatible>(name: S) -> &'a BnStr {
+ let mut name = QualifiedName::from(name);
+ unsafe { BnStr::from_raw(BNGenerateAutoDemangledTypeId(&mut name.0)) }
+ }
+}
+
+impl fmt::Display for Type {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", unsafe {
+ BnString::from_raw(BNGetTypeString(self.handle, ptr::null_mut()))
+ })
}
}
+unsafe impl Send for Type {}
+unsafe impl Sync for Type {}
+
unsafe impl RefCountable for Type {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Ref::new(Self {
handle: BNNewTypeReference(handle.handle),
+ confidence: handle.confidence,
})
}
@@ -40,17 +238,187 @@ unsafe impl RefCountable for Type {
}
}
-#[repr(C)]
-pub struct QualifiedName {
- object: BNQualifiedName,
+impl ToOwned for Type {
+ type Owned = Ref<Self>;
+
+ fn to_owned(&self) -> Self::Owned {
+ unsafe { RefCountable::inc_ref(self) }
+ }
+}
+
+///////////////
+// Structure
+
+#[derive(PartialEq, Eq, Hash)]
+pub struct Structure {
+ pub builder: *mut BNStructureBuilder,
+ pub handle: Option<*mut BNStructure>,
+}
+
+// TODO : Throw asserts or return results?
+impl Structure {
+ // TODO : Turn this into a real docstring
+ // // Includes
+ // use binaryninja::types::{Structure, Type};
+
+ // // Define struct, set size (in bytes)
+ // let mut my_custom_struct = Structure::new();
+ // my_custom_struct.set_width(17);
+
+ // // Create some fields for the struct
+ // let field_1 = Type::named_int(5, false, "my_weird_int_type");
+ // let field_2 = Type::int(4, false);
+ // let field_3 = Type::int(8, false);
+
+ // // Assign those fields
+ // my_custom_struct.append(&field_1, "field_4");
+ // my_custom_struct.insert(&field_1, "field_1", 0);
+ // my_custom_struct.insert(&field_2, "field_2", 5);
+ // my_custom_struct.insert(&field_3, "field_3", 9);
+
+ // // Convert structure to type
+ // let my_custom_structure_type = Type::structure_type(&mut my_custom_struct);
+
+ // // Add the struct to the binary view to use in analysis
+ // let bv = unsafe { BinaryView::from_raw(view) };
+ // bv.define_user_type("my_custom_struct", &my_custom_structure_type);
+
+ pub fn new() -> Self {
+ Structure {
+ builder: unsafe { BNCreateStructureBuilder() },
+ handle: None,
+ }
+ }
+
+ pub(crate) fn handle(&mut self) -> *mut BNStructure {
+ if let Some(handle) = self.handle {
+ handle
+ } else {
+ unsafe {
+ self.handle = Some(BNFinalizeStructureBuilder(self.builder));
+ BNFreeStructureBuilder(self.builder);
+ }
+ self.handle.unwrap()
+ }
+ }
+
+ pub fn set_width(&self, width: u64) {
+ assert!(self.handle.is_none());
+ unsafe {
+ BNSetStructureBuilderWidth(self.builder, width);
+ }
+ }
+
+ pub fn get_width(&self) -> u64 {
+ if let Some(structure_handle) = self.handle {
+ unsafe { BNGetStructureWidth(structure_handle) }
+ } else {
+ unsafe { BNGetStructureBuilderWidth(self.builder) }
+ }
+ }
+
+ pub fn append<S: BnStrCompatible>(&self, t: &Type, name: S) {
+ assert!(self.handle.is_none());
+ let mut type_conf = TypeWithConfidence::new(t, t.confidence);
+ let name = name.as_bytes_with_nul();
+ unsafe {
+ BNAddStructureBuilderMember(
+ self.builder,
+ &mut type_conf.0,
+ name.as_ref().as_ptr() as _,
+ );
+ }
+ }
+
+ pub fn insert<S: BnStrCompatible>(&self, t: &Type, name: S, offset: u64) {
+ assert!(self.handle.is_none());
+ let mut type_conf = TypeWithConfidence::new(t, t.confidence);
+ let name = name.as_bytes_with_nul();
+ unsafe {
+ BNAddStructureBuilderMemberAtOffset(
+ self.builder,
+ &mut type_conf.0,
+ name.as_ref().as_ptr() as _,
+ offset,
+ );
+ }
+ }
+
+ // TODO : The other methods in the python version (alignment, packed, type, members, remove, replace, etc)
}
+// TODO : Use
+// #[derive(PartialEq, Eq, Hash)]
+// pub struct StructureMember {
+// pub(crate) handle: *mut BNStructureMember,
+// }
+
+// impl StructureMember {
+// // pub fn new() -> Self {}
+// }
+
+////////////////////////
+// BoolWithConfidence
+
+pub struct BoolWithConfidence(BNBoolWithConfidence);
+
+impl BoolWithConfidence {
+ pub fn new(value: bool, confidence: u8) -> Self {
+ BoolWithConfidence(BNBoolWithConfidence { value, confidence })
+ }
+}
+
+////////////////////////
+// TypeWithConfidence
+
+pub struct TypeWithConfidence(BNTypeWithConfidence);
+
+impl TypeWithConfidence {
+ pub fn new(t: &Type, confidence: u8) -> Self {
+ TypeWithConfidence(BNTypeWithConfidence {
+ type_: t.handle,
+ confidence,
+ })
+ }
+}
+
+////////////////////////
+// NamedTypeReference
+
+#[derive(PartialEq, Eq, Hash)]
+pub struct NamedTypeReference {
+ pub(crate) handle: *mut BNNamedTypeReference,
+}
+
+impl NamedTypeReference {
+ pub fn new<S: BnStrCompatible>(
+ type_class: NamedTypeReferenceClass,
+ type_id: S,
+ mut name: QualifiedName,
+ ) -> Self {
+ let type_id = type_id.as_bytes_with_nul();
+
+ NamedTypeReference {
+ handle: unsafe {
+ BNCreateNamedType(type_class, type_id.as_ref().as_ptr() as _, &mut name.0)
+ },
+ }
+ }
+}
+
+///////////////////
+// QualifiedName
+
+#[repr(transparent)]
+pub struct QualifiedName(pub(crate) BNQualifiedName);
+
impl QualifiedName {
+ // TODO : I think this is bad
pub fn string(&self) -> String {
use std::ffi::CStr;
unsafe {
- slice::from_raw_parts(self.object.name, self.object.nameCount)
+ slice::from_raw_parts(self.0.name, self.0.nameCount)
.iter()
.map(|c| CStr::from_ptr(*c).to_string_lossy())
.collect::<Vec<_>>()
@@ -59,34 +427,49 @@ impl QualifiedName {
}
}
+impl<S: BnStrCompatible> From<S> for QualifiedName {
+ fn from(name: S) -> Self {
+ let join = BnString::new("::");
+ let name = name.as_bytes_with_nul();
+ let mut list = vec![name.as_ref().as_ptr() as *const _];
+
+ QualifiedName(BNQualifiedName {
+ name: unsafe { BNAllocStringList(list.as_mut_ptr(), 1) },
+ join: join.into_raw(),
+ nameCount: 1,
+ })
+ }
+}
+
impl Drop for QualifiedName {
fn drop(&mut self) {
- unsafe { BNFreeQualifiedName(&mut self.object); }
+ unsafe {
+ BNFreeQualifiedName(&mut self.0);
+ }
}
}
-#[repr(C)]
-pub struct QualifiedNameAndType {
- object: BNQualifiedNameAndType,
-}
+//////////////////////////
+// QualifiedNameAndType
+
+#[repr(transparent)]
+pub struct QualifiedNameAndType(pub(crate) BNQualifiedNameAndType);
impl QualifiedNameAndType {
pub fn name(&self) -> &QualifiedName {
- unsafe {
- mem::transmute(&self.object.name)
- }
+ unsafe { mem::transmute(&self.0.name) }
}
pub fn type_object(&self) -> Guard<Type> {
- unsafe {
- Guard::new(Type::from_raw(self.object.type_), self)
- }
+ unsafe { Guard::new(Type::from_raw(self.0.type_), self) }
}
}
impl Drop for QualifiedNameAndType {
fn drop(&mut self) {
- unsafe { BNFreeQualifiedNameAndType(&mut self.object); }
+ unsafe {
+ BNFreeQualifiedNameAndType(&mut self.0);
+ }
}
}
@@ -106,4 +489,3 @@ unsafe impl<'a> CoreOwnedArrayWrapper<'a> for QualifiedNameAndType {
mem::transmute(raw)
}
}
-