#![allow(unused)]
use binaryninjacore_sys::*;
use crate::{
architecture::{Architecture, CoreArchitecture},
binary_view::{BinaryView, BinaryViewExt},
calling_convention::CoreCallingConvention,
rc::*,
string::{BnStrCompatible, BnString},
};
use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
use crate::string::{raw_to_string, strings_to_string_list};
use crate::variable::{Variable, VariableSourceType};
use std::borrow::Cow;
use std::num::NonZeroUsize;
use std::ops::{Index, IndexMut};
use std::{
collections::HashSet,
ffi::CStr,
fmt::{Debug, Display, Formatter},
hash::{Hash, Hasher},
iter::IntoIterator,
};
pub type StructureType = BNStructureVariant;
pub type ReferenceType = BNReferenceType;
pub type TypeClass = BNTypeClass;
pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
pub type MemberAccess = BNMemberAccess;
pub type MemberScope = BNMemberScope;
pub type IntegerDisplayType = BNIntegerDisplayType;
#[derive(PartialEq, Eq, Hash)]
pub struct TypeBuilder {
pub(crate) handle: *mut BNTypeBuilder,
}
impl TypeBuilder {
pub fn new(t: &Type) -> Self {
unsafe { Self::from_raw(BNCreateTypeBuilderFromType(t.handle)) }
}
pub(crate) unsafe fn from_raw(handle: *mut BNTypeBuilder) -> Self {
debug_assert!(!handle.is_null());
Self { handle }
}
pub fn finalize(&self) -> Ref<Type> {
unsafe { Type::ref_from_raw(BNFinalizeTypeBuilder(self.handle)) }
}
pub fn set_can_return<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
let mut bool_with_confidence = value.into().into();
unsafe { BNSetFunctionTypeBuilderCanReturn(self.handle, &mut bool_with_confidence) };
self
}
pub fn set_pure<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
let mut bool_with_confidence = value.into().into();
unsafe { BNSetTypeBuilderPure(self.handle, &mut bool_with_confidence) };
self
}
pub fn set_const<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
let mut bool_with_confidence = value.into().into();
unsafe { BNTypeBuilderSetConst(self.handle, &mut bool_with_confidence) };
self
}
pub fn set_volatile<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
let mut bool_with_confidence = value.into().into();
unsafe { BNTypeBuilderSetVolatile(self.handle, &mut bool_with_confidence) };
self
}
pub fn type_class(&self) -> TypeClass {
unsafe { BNGetTypeBuilderClass(self.handle) }
}
pub fn width(&self) -> u64 {
unsafe { BNGetTypeBuilderWidth(self.handle) }
}
pub fn alignment(&self) -> usize {
unsafe { BNGetTypeBuilderAlignment(self.handle) }
}
pub fn is_signed(&self) -> Conf<bool> {
unsafe { BNIsTypeBuilderSigned(self.handle).into() }
}
pub fn is_const(&self) -> Conf<bool> {
unsafe { BNIsTypeBuilderConst(self.handle).into() }
}
pub fn is_volatile(&self) -> Conf<bool> {
unsafe { BNIsTypeBuilderVolatile(self.handle).into() }
}
pub fn is_floating_point(&self) -> bool {
unsafe { BNIsTypeBuilderFloatingPoint(self.handle) }
}
pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
match raw_target.type_.is_null() {
false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
true => None,
}
}
pub fn target(&self) -> Option<Conf<Ref<Type>>> {
self.child_type()
}
pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
self.child_type()
}
pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
self.child_type()
}
pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
let raw_convention_confidence = unsafe { BNGetTypeBuilderCallingConvention(self.handle) };
match raw_convention_confidence.convention.is_null() {
false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
raw_convention_confidence,
)),
true => None,
}
}
pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
unsafe {
let mut count = 0;
let raw_parameters_ptr = BNGetTypeBuilderParameters(self.handle, &mut count);
match raw_parameters_ptr.is_null() {
false => {
let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
let parameters = raw_parameters
.iter()
.map(FunctionParameter::from_raw)
.collect();
BNFreeTypeParameterList(raw_parameters_ptr, count);
Some(parameters)
}
true => None,
}
}
}
pub fn has_variable_arguments(&self) -> Conf<bool> {
unsafe { BNTypeBuilderHasVariableArguments(self.handle).into() }
}
pub fn can_return(&self) -> Conf<bool> {
unsafe { BNFunctionTypeBuilderCanReturn(self.handle).into() }
}
pub fn pure(&self) -> Conf<bool> {
unsafe { BNIsTypeBuilderPure(self.handle).into() }
}
pub fn get_structure(&self) -> Option<Ref<Structure>> {
let raw_struct_ptr = unsafe { BNGetTypeBuilderStructure(self.handle) };
match raw_struct_ptr.is_null() {
false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
true => None,
}
}
pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
let raw_enum_ptr = unsafe { BNGetTypeBuilderEnumeration(self.handle) };
match raw_enum_ptr.is_null() {
false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
true => None,
}
}
pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
let raw_type_ref_ptr = unsafe { BNGetTypeBuilderNamedTypeReference(self.handle) };
match raw_type_ref_ptr.is_null() {
false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
true => None,
}
}
pub fn count(&self) -> u64 {
unsafe { BNGetTypeBuilderElementCount(self.handle) }
}
pub fn offset(&self) -> u64 {
unsafe { BNGetTypeBuilderOffset(self.handle) }
}
pub fn stack_adjustment(&self) -> Conf<i64> {
unsafe { BNGetTypeBuilderStackAdjustment(self.handle).into() }
}
pub fn void() -> Self {
unsafe { Self::from_raw(BNCreateVoidTypeBuilder()) }
}
pub fn bool() -> Self {
unsafe { Self::from_raw(BNCreateBoolTypeBuilder()) }
}
pub fn char() -> Self {
Self::int(1, true)
}
pub fn int(width: usize, is_signed: bool) -> Self {
let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
unsafe {
Self::from_raw(BNCreateIntegerTypeBuilder(
width,
&mut is_signed,
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 = Conf::new(is_signed, MAX_CONFIDENCE).into();
let alt_name = alt_name.into_bytes_with_nul(); unsafe {
Self::from_raw(BNCreateIntegerTypeBuilder(
width,
&mut is_signed,
alt_name.as_ref().as_ptr() as _,
))
}
}
pub fn float(width: usize) -> Self {
unsafe {
Self::from_raw(BNCreateFloatTypeBuilder(
width,
BnString::new("").as_ptr() as *mut _,
))
}
}
pub fn named_float<S: BnStrCompatible>(width: usize, alt_name: S) -> Self {
let alt_name = alt_name.into_bytes_with_nul(); unsafe {
Self::from_raw(BNCreateFloatTypeBuilder(
width,
alt_name.as_ref().as_ptr() as _,
))
}
}
pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Self {
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe { Self::from_raw(BNCreateArrayTypeBuilder(&owned_raw_ty, count)) }
}
pub fn enumeration<T: Into<Conf<bool>>>(
enumeration: &Enumeration,
width: NonZeroUsize,
is_signed: T,
) -> Self {
unsafe {
Self::from_raw(BNCreateEnumerationTypeBuilder(
std::ptr::null_mut(),
enumeration.handle,
width.get(),
&mut is_signed.into().into(),
))
}
}
pub fn structure(structure_type: &Structure) -> Self {
unsafe { Self::from_raw(BNCreateStructureTypeBuilder(structure_type.handle)) }
}
pub fn named_type(type_reference: NamedTypeReference) -> Self {
let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
unsafe {
Self::from_raw(BNCreateNamedTypeReferenceBuilder(
type_reference.handle,
0,
1,
&mut is_const,
&mut is_volatile,
))
}
}
pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Self {
let mut raw_name = QualifiedName::into_raw(name.into());
let id = c"";
let result = unsafe {
Self::from_raw(BNCreateNamedTypeReferenceBuilderFromTypeAndId(
id.as_ptr() as *mut _,
&mut raw_name,
t.handle,
))
};
QualifiedName::free_raw(raw_name);
result
}
pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilder(
arch.as_ref().handle,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
))
}
}
pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
let mut is_const = Conf::new(true, MAX_CONFIDENCE).into();
let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilder(
arch.as_ref().handle,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
))
}
}
pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
ty: T,
size: usize,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Self {
let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilderOfWidth(
size,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
))
}
}
pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
arch: &A,
ty: T,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Self {
let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::from_raw(BNCreatePointerTypeBuilder(
arch.as_ref().handle,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
))
}
}
}
impl Display for TypeBuilder {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", unsafe {
BnString::from_raw(BNGetTypeBuilderString(self.handle, std::ptr::null_mut()))
})
}
}
impl Drop for TypeBuilder {
fn drop(&mut self) {
unsafe { BNFreeTypeBuilder(self.handle) };
}
}
#[repr(transparent)]
pub struct Type {
pub(crate) handle: *mut BNType,
}
impl Type {
pub(crate) unsafe fn from_raw(handle: *mut BNType) -> Self {
debug_assert!(!handle.is_null());
Self { handle }
}
pub(crate) unsafe fn ref_from_raw(handle: *mut BNType) -> Ref<Self> {
debug_assert!(!handle.is_null());
Ref::new(Self { handle })
}
pub fn to_builder(&self) -> TypeBuilder {
TypeBuilder::new(self)
}
pub fn type_class(&self) -> TypeClass {
unsafe { BNGetTypeClass(self.handle) }
}
pub fn width(&self) -> u64 {
unsafe { BNGetTypeWidth(self.handle) }
}
pub fn alignment(&self) -> usize {
unsafe { BNGetTypeAlignment(self.handle) }
}
pub fn is_signed(&self) -> Conf<bool> {
unsafe { BNIsTypeSigned(self.handle).into() }
}
pub fn is_const(&self) -> Conf<bool> {
unsafe { BNIsTypeConst(self.handle).into() }
}
pub fn is_volatile(&self) -> Conf<bool> {
unsafe { BNIsTypeVolatile(self.handle).into() }
}
pub fn is_floating_point(&self) -> bool {
unsafe { BNIsTypeFloatingPoint(self.handle) }
}
pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
let raw_target = unsafe { BNGetChildType(self.handle) };
match raw_target.type_.is_null() {
false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
true => None,
}
}
pub fn target(&self) -> Option<Conf<Ref<Type>>> {
self.child_type()
}
pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
self.child_type()
}
pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
self.child_type()
}
pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
let convention_confidence = unsafe { BNGetTypeCallingConvention(self.handle) };
match convention_confidence.convention.is_null() {
false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
convention_confidence,
)),
true => None,
}
}
pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
unsafe {
let mut count = 0;
let raw_parameters_ptr = BNGetTypeParameters(self.handle, &mut count);
match raw_parameters_ptr.is_null() {
false => {
let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
let parameters = raw_parameters
.iter()
.map(FunctionParameter::from_raw)
.collect();
BNFreeTypeParameterList(raw_parameters_ptr, count);
Some(parameters)
}
true => None,
}
}
}
pub fn has_variable_arguments(&self) -> Conf<bool> {
unsafe { BNTypeHasVariableArguments(self.handle).into() }
}
pub fn can_return(&self) -> Conf<bool> {
unsafe { BNFunctionTypeCanReturn(self.handle).into() }
}
pub fn pure(&self) -> Conf<bool> {
unsafe { BNIsTypePure(self.handle).into() }
}
pub fn get_structure(&self) -> Option<Ref<Structure>> {
let raw_struct_ptr = unsafe { BNGetTypeStructure(self.handle) };
match raw_struct_ptr.is_null() {
false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
true => None,
}
}
pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
let raw_enum_ptr = unsafe { BNGetTypeEnumeration(self.handle) };
match raw_enum_ptr.is_null() {
false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
true => None,
}
}
pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
let raw_type_ref_ptr = unsafe { BNGetTypeNamedTypeReference(self.handle) };
match raw_type_ref_ptr.is_null() {
false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
true => None,
}
}
pub fn count(&self) -> u64 {
unsafe { BNGetTypeElementCount(self.handle) }
}
pub fn offset(&self) -> u64 {
unsafe { BNGetTypeOffset(self.handle) }
}
pub fn stack_adjustment(&self) -> Conf<i64> {
unsafe { BNGetTypeStackAdjustment(self.handle).into() }
}
pub fn registered_name(&self) -> Option<Ref<NamedTypeReference>> {
let raw_type_ref_ptr = unsafe { BNGetRegisteredTypeName(self.handle) };
match raw_type_ref_ptr.is_null() {
false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
true => None,
}
}
pub fn void() -> Ref<Self> {
unsafe { Self::ref_from_raw(BNCreateVoidType()) }
}
pub fn bool() -> Ref<Self> {
unsafe { Self::ref_from_raw(BNCreateBoolType()) }
}
pub fn char() -> Ref<Self> {
Self::int(1, true)
}
pub fn wide_char(width: usize) -> Ref<Self> {
unsafe {
Self::ref_from_raw(BNCreateWideCharType(
width,
BnString::new("").as_ptr() as *mut _,
))
}
}
pub fn int(width: usize, is_signed: bool) -> Ref<Self> {
let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
unsafe {
Self::ref_from_raw(BNCreateIntegerType(
width,
&mut is_signed,
BnString::new("").as_ptr() as *mut _,
))
}
}
pub fn named_int<S: BnStrCompatible>(width: usize, is_signed: bool, alt_name: S) -> Ref<Self> {
let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
let alt_name = alt_name.into_bytes_with_nul(); unsafe {
Self::ref_from_raw(BNCreateIntegerType(
width,
&mut is_signed,
alt_name.as_ref().as_ptr() as _,
))
}
}
pub fn float(width: usize) -> Ref<Self> {
unsafe {
Self::ref_from_raw(BNCreateFloatType(
width,
BnString::new("").as_ptr() as *mut _,
))
}
}
pub fn named_float<S: BnStrCompatible>(width: usize, alt_name: S) -> Ref<Self> {
let alt_name = alt_name.into_bytes_with_nul(); unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) }
}
pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Ref<Self> {
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe { Self::ref_from_raw(BNCreateArrayType(&owned_raw_ty, count)) }
}
pub fn enumeration<T: Into<Conf<bool>>>(
enumeration: &Enumeration,
width: NonZeroUsize,
is_signed: T,
) -> Ref<Self> {
unsafe {
Self::ref_from_raw(BNCreateEnumerationType(
std::ptr::null_mut(),
enumeration.handle,
width.get(),
&mut is_signed.into().into(),
))
}
}
pub fn structure(structure: &Structure) -> Ref<Self> {
unsafe { Self::ref_from_raw(BNCreateStructureType(structure.handle)) }
}
pub fn named_type(type_reference: &NamedTypeReference) -> Ref<Self> {
let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
unsafe {
Self::ref_from_raw(BNCreateNamedTypeReference(
type_reference.handle,
0,
1,
&mut is_const,
&mut is_volatile,
))
}
}
pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Ref<Self> {
let mut raw_name = QualifiedName::into_raw(name.into());
let id = c"";
let result = unsafe {
Self::ref_from_raw(BNCreateNamedTypeReferenceFromTypeAndId(
id.as_ptr(),
&mut raw_name,
t.handle,
))
};
QualifiedName::free_raw(raw_name);
result
}
pub fn function<'a, T: Into<Conf<&'a Type>>>(
return_type: T,
parameters: Vec<FunctionParameter>,
variable_arguments: bool,
) -> Ref<Self> {
let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
let mut raw_calling_convention: BNCallingConventionWithConfidence =
BNCallingConventionWithConfidence {
convention: std::ptr::null_mut(),
confidence: MIN_CONFIDENCE,
};
let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
let mut raw_parameters = parameters
.into_iter()
.map(FunctionParameter::into_raw)
.collect::<Vec<_>>();
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
regs: std::ptr::null_mut(),
count: 0,
confidence: 0,
};
let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
&mut owned_raw_return_type,
&mut raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
&mut variable_arguments,
&mut can_return,
&mut stack_adjust,
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
&mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
};
for raw_param in raw_parameters {
FunctionParameter::free_raw(raw_param);
}
result
}
pub fn function_with_opts<
'a,
T: Into<Conf<&'a Type>>,
C: Into<Conf<Ref<CoreCallingConvention>>>,
>(
return_type: T,
parameters: &[FunctionParameter],
variable_arguments: bool,
calling_convention: C,
stack_adjust: Conf<i64>,
) -> Ref<Self> {
let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
let mut owned_raw_calling_convention =
Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
let mut stack_adjust = stack_adjust.into();
let mut raw_parameters = parameters
.iter()
.cloned()
.map(FunctionParameter::into_raw)
.collect::<Vec<_>>();
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
regs: std::ptr::null_mut(),
count: 0,
confidence: 0,
};
let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
&mut owned_raw_return_type,
&mut owned_raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
&mut variable_arguments,
&mut can_return,
&mut stack_adjust,
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
&mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
};
for raw_param in raw_parameters {
FunctionParameter::free_raw(raw_param);
}
result
}
pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Ref<Self> {
let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerType(
arch.as_ref().handle,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
))
}
}
pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
arch: &A,
ty: T,
) -> Ref<Self> {
let mut is_const = Conf::new(true, MAX_CONFIDENCE).into();
let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerType(
arch.as_ref().handle,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ReferenceType::PointerReferenceType,
))
}
}
pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
ty: T,
size: usize,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Ref<Self> {
let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerTypeOfWidth(
size,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
))
}
}
pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
arch: &A,
ty: T,
is_const: bool,
is_volatile: bool,
ref_type: Option<ReferenceType>,
) -> Ref<Self> {
let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
Self::ref_from_raw(BNCreatePointerType(
arch.as_ref().handle,
&owned_raw_ty,
&mut is_const,
&mut is_volatile,
ref_type.unwrap_or(ReferenceType::PointerReferenceType),
))
}
}
pub fn generate_auto_demangled_type_id<T: Into<QualifiedName>>(name: T) -> BnString {
let mut raw_name = QualifiedName::into_raw(name.into());
let type_id = unsafe { BnString::from_raw(BNGenerateAutoDemangledTypeId(&mut raw_name)) };
QualifiedName::free_raw(raw_name);
type_id
}
}
impl Display for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", unsafe {
BnString::from_raw(BNGetTypeString(
self.handle,
std::ptr::null_mut(),
BNTokenEscapingType::NoTokenEscapingType,
))
})
}
}
impl Debug for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Type")
.field("type_class", &self.type_class())
.field("width", &self.width())
.field("alignment", &self.alignment())
.field("is_signed", &self.is_signed())
.field("is_const", &self.is_const())
.field("is_volatile", &self.is_volatile())
.field("child_type", &self.child_type())
.field("calling_convention", &self.calling_convention())
.field("parameters", &self.parameters())
.field("has_variable_arguments", &self.has_variable_arguments())
.field("can_return", &self.can_return())
.field("pure", &self.pure())
.field("get_structure", &self.get_structure())
.field("get_enumeration", &self.get_enumeration())
.field("get_named_type_reference", &self.get_named_type_reference())
.field("count", &self.count())
.field("offset", &self.offset())
.field("stack_adjustment", &self.stack_adjustment())
.field("registered_name", &self.registered_name())
.finish()
}
}
impl PartialEq for Type {
fn eq(&self, other: &Self) -> bool {
unsafe { BNTypesEqual(self.handle, other.handle) }
}
}
impl Eq for Type {}
impl Hash for Type {
fn hash<H: Hasher>(&self, state: &mut H) {
self.handle.hash(state);
}
}
unsafe impl Send for Type {}
unsafe impl Sync for Type {}
unsafe impl RefCountable for Type {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Self::ref_from_raw(BNNewTypeReference(handle.handle))
}
unsafe fn dec_ref(handle: &Self) {
BNFreeType(handle.handle);
}
}
impl ToOwned for Type {
type Owned = Ref<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
impl CoreArrayProvider for Type {
type Raw = *mut BNType;
type Context = ();
type Wrapped<'a> = &'a Self;
}
unsafe impl CoreArrayProviderInner for Type {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeTypeList(raw, count)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
std::mem::transmute(raw)
}
}
pub struct ComponentReferencedType;
impl CoreArrayProvider for ComponentReferencedType {
type Raw = *mut BNType;
type Context = ();
type Wrapped<'a> = &'a Type;
}
unsafe impl CoreArrayProviderInner for ComponentReferencedType {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNComponentFreeReferencedTypes(raw, count)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
std::mem::transmute(raw)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FunctionParameter {
pub ty: Conf<Ref<Type>>,
pub name: String,
pub location: Option<Variable>,
}
impl FunctionParameter {
pub(crate) fn from_raw(value: &BNFunctionParameter) -> Self {
let name = if value.name.is_null() {
if value.location.type_ == VariableSourceType::RegisterVariableSourceType {
format!("reg_{}", value.location.storage)
} else if value.location.type_ == VariableSourceType::StackVariableSourceType {
format!("arg_{}", value.location.storage)
} else {
String::new()
}
} else {
raw_to_string(value.name as *const _).unwrap()
};
Self {
ty: Conf::new(
unsafe { Type::from_raw(value.type_).to_owned() },
value.typeConfidence,
),
name,
location: match value.defaultLocation {
false => Some(Variable::from(value.location)),
true => None,
},
}
}
pub(crate) fn from_owned_raw(value: BNFunctionParameter) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNFunctionParameter {
let bn_name = BnString::new(value.name);
BNFunctionParameter {
name: BnString::into_raw(bn_name),
type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
typeConfidence: value.ty.confidence,
defaultLocation: value.location.is_none(),
location: value.location.map(Into::into).unwrap_or_default(),
}
}
pub(crate) fn free_raw(value: BNFunctionParameter) {
let _ = unsafe { BnString::from_raw(value.name) };
let _ = unsafe { Type::ref_from_raw(value.type_) };
}
pub fn new<T: Into<Conf<Ref<Type>>>>(ty: T, name: String, location: Option<Variable>) -> Self {
Self {
ty: ty.into(),
name,
location,
}
}
}
impl CoreArrayProvider for (&str, Variable, &Type) {
type Raw = BNVariableNameAndType;
type Context = ();
type Wrapped<'a>
= (&'a str, Variable, &'a Type)
where
Self: 'a;
}
unsafe impl CoreArrayProviderInner for (&str, Variable, &Type) {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeVariableNameAndTypeList(raw, count)
}
unsafe fn wrap_raw<'a>(
raw: &'a Self::Raw,
_context: &'a Self::Context,
) -> (&'a str, Variable, &'a Type) {
let name = CStr::from_ptr(raw.name).to_str().unwrap();
let var = Variable::from(raw.var);
let var_type = &*(raw.type_ as *mut Type);
(name, var, var_type)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct EnumerationMember {
pub name: String,
pub value: u64,
pub default: bool,
}
impl EnumerationMember {
pub(crate) fn from_raw(value: &BNEnumerationMember) -> Self {
Self {
name: raw_to_string(value.name).unwrap(),
value: value.value,
default: value.isDefault,
}
}
pub(crate) fn from_owned_raw(value: BNEnumerationMember) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNEnumerationMember {
let bn_name = BnString::new(value.name);
BNEnumerationMember {
name: BnString::into_raw(bn_name),
value: value.value,
isDefault: value.default,
}
}
pub(crate) fn free_raw(value: BNEnumerationMember) {
let _ = unsafe { BnString::from_raw(value.name) };
}
pub fn new(name: String, value: u64, default: bool) -> Self {
Self {
name,
value,
default,
}
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct EnumerationBuilder {
pub(crate) handle: *mut BNEnumerationBuilder,
}
impl EnumerationBuilder {
pub fn new() -> Self {
Self {
handle: unsafe { BNCreateEnumerationBuilder() },
}
}
pub(crate) unsafe fn from_raw(handle: *mut BNEnumerationBuilder) -> Self {
Self { handle }
}
pub fn finalize(&self) -> Ref<Enumeration> {
unsafe { Enumeration::ref_from_raw(BNFinalizeEnumerationBuilder(self.handle)) }
}
pub fn append<S: BnStrCompatible>(&mut self, name: S) -> &mut Self {
let name = name.into_bytes_with_nul();
unsafe {
BNAddEnumerationBuilderMember(self.handle, name.as_ref().as_ptr() as _);
}
self
}
pub fn insert<S: BnStrCompatible>(&mut self, name: S, value: u64) -> &mut Self {
let name = name.into_bytes_with_nul();
unsafe {
BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_ref().as_ptr() as _, value);
}
self
}
pub fn replace<S: BnStrCompatible>(&mut self, id: usize, name: S, value: u64) -> &mut Self {
let name = name.into_bytes_with_nul();
unsafe {
BNReplaceEnumerationBuilderMember(self.handle, id, name.as_ref().as_ptr() as _, value);
}
self
}
pub fn remove(&mut self, id: usize) -> &mut Self {
unsafe {
BNRemoveEnumerationBuilderMember(self.handle, id);
}
self
}
pub fn members(&self) -> Vec<EnumerationMember> {
unsafe {
let mut count = 0;
let members_raw_ptr = BNGetEnumerationBuilderMembers(self.handle, &mut count);
let members_raw: &[BNEnumerationMember] =
std::slice::from_raw_parts(members_raw_ptr, count);
let members = members_raw
.iter()
.map(EnumerationMember::from_raw)
.collect();
BNFreeEnumerationMemberList(members_raw_ptr, count);
members
}
}
}
impl Default for EnumerationBuilder {
fn default() -> Self {
Self::new()
}
}
impl From<&Enumeration> for EnumerationBuilder {
fn from(enumeration: &Enumeration) -> Self {
unsafe {
Self::from_raw(BNCreateEnumerationBuilderFromEnumeration(
enumeration.handle,
))
}
}
}
impl Drop for EnumerationBuilder {
fn drop(&mut self) {
unsafe { BNFreeEnumerationBuilder(self.handle) };
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct Enumeration {
pub(crate) handle: *mut BNEnumeration,
}
impl Enumeration {
pub(crate) unsafe fn ref_from_raw(handle: *mut BNEnumeration) -> Ref<Self> {
debug_assert!(!handle.is_null());
Ref::new(Self { handle })
}
pub fn builder() -> EnumerationBuilder {
EnumerationBuilder::new()
}
pub fn members(&self) -> Vec<EnumerationMember> {
unsafe {
let mut count = 0;
let members_raw_ptr = BNGetEnumerationMembers(self.handle, &mut count);
debug_assert!(!members_raw_ptr.is_null());
let members_raw: &[BNEnumerationMember] =
std::slice::from_raw_parts(members_raw_ptr, count);
let members = members_raw
.iter()
.map(EnumerationMember::from_raw)
.collect();
BNFreeEnumerationMemberList(members_raw_ptr, count);
members
}
}
}
impl Debug for Enumeration {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Enumeration")
.field("members", &self.members())
.finish()
}
}
unsafe impl RefCountable for Enumeration {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Self::ref_from_raw(BNNewEnumerationReference(handle.handle))
}
unsafe fn dec_ref(handle: &Self) {
BNFreeEnumeration(handle.handle);
}
}
impl ToOwned for Enumeration {
type Owned = Ref<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct StructureBuilder {
pub(crate) handle: *mut BNStructureBuilder,
}
impl StructureBuilder {
pub fn new() -> Self {
Self {
handle: unsafe { BNCreateStructureBuilder() },
}
}
pub(crate) unsafe fn from_raw(handle: *mut BNStructureBuilder) -> Self {
debug_assert!(!handle.is_null());
Self { handle }
}
pub fn finalize(&mut self) -> Ref<Structure> {
let raw_struct_ptr = unsafe { BNFinalizeStructureBuilder(self.handle) };
unsafe { Structure::ref_from_raw(raw_struct_ptr) }
}
pub fn width(&mut self, width: u64) -> &mut Self {
unsafe {
BNSetStructureBuilderWidth(self.handle, width);
}
self
}
pub fn alignment(&mut self, alignment: usize) -> &mut Self {
unsafe {
BNSetStructureBuilderAlignment(self.handle, alignment);
}
self
}
pub fn packed(&mut self, packed: bool) -> &mut Self {
unsafe {
BNSetStructureBuilderPacked(self.handle, packed);
}
self
}
pub fn structure_type(&mut self, t: StructureType) -> &mut Self {
unsafe { BNSetStructureBuilderType(self.handle, t) };
self
}
pub fn pointer_offset(&mut self, offset: i64) -> &mut Self {
unsafe { BNSetStructureBuilderPointerOffset(self.handle, offset) };
self
}
pub fn propagates_data_var_refs(&mut self, propagates: bool) -> &mut Self {
unsafe { BNSetStructureBuilderPropagatesDataVariableReferences(self.handle, propagates) };
self
}
pub fn base_structures(&mut self, bases: &[BaseStructure]) -> &mut Self {
let raw_base_structs: Vec<BNBaseStructure> =
bases.iter().map(BaseStructure::into_owned_raw).collect();
unsafe {
BNSetBaseStructuresForStructureBuilder(
self.handle,
raw_base_structs.as_ptr() as *mut _,
raw_base_structs.len(),
)
};
self
}
pub fn append<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
&mut self,
ty: T,
name: S,
access: MemberAccess,
scope: MemberScope,
) -> &mut Self {
let name = name.into_bytes_with_nul();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
BNAddStructureBuilderMember(
self.handle,
&owned_raw_ty,
name.as_ref().as_ptr() as _,
access,
scope,
);
}
self
}
pub fn insert_member(
&mut self,
member: StructureMember,
overwrite_existing: bool,
) -> &mut Self {
self.insert(
&member.ty,
member.name,
member.offset,
overwrite_existing,
member.access,
member.scope,
);
self
}
pub fn insert<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
&mut self,
ty: T,
name: S,
offset: u64,
overwrite_existing: bool,
access: MemberAccess,
scope: MemberScope,
) -> &mut Self {
let name = name.into_bytes_with_nul();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
BNAddStructureBuilderMemberAtOffset(
self.handle,
&owned_raw_ty,
name.as_ref().as_ptr() as _,
offset,
overwrite_existing,
access,
scope,
);
}
self
}
pub fn replace<'a, S: BnStrCompatible, T: Into<Conf<&'a Type>>>(
&mut self,
index: usize,
ty: T,
name: S,
overwrite_existing: bool,
) -> &mut Self {
let name = name.into_bytes_with_nul();
let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
unsafe {
BNReplaceStructureBuilderMember(
self.handle,
index,
&owned_raw_ty,
name.as_ref().as_ptr() as _,
overwrite_existing,
)
}
self
}
pub fn remove(&mut self, index: usize) -> &mut Self {
unsafe { BNRemoveStructureBuilderMember(self.handle, index) };
self
}
pub fn current_width(&self) -> u64 {
unsafe { BNGetStructureBuilderWidth(self.handle) }
}
}
impl From<&Structure> for StructureBuilder {
fn from(structure: &Structure) -> StructureBuilder {
unsafe { Self::from_raw(BNCreateStructureBuilderFromStructure(structure.handle)) }
}
}
impl From<Vec<StructureMember>> for StructureBuilder {
fn from(members: Vec<StructureMember>) -> StructureBuilder {
let mut builder = StructureBuilder::new();
for member in members {
builder.insert_member(member, false);
}
builder
}
}
impl Drop for StructureBuilder {
fn drop(&mut self) {
unsafe { BNFreeStructureBuilder(self.handle) };
}
}
impl Default for StructureBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct Structure {
pub(crate) handle: *mut BNStructure,
}
impl Structure {
pub(crate) unsafe fn ref_from_raw(handle: *mut BNStructure) -> Ref<Self> {
debug_assert!(!handle.is_null());
Ref::new(Self { handle })
}
pub fn builder() -> StructureBuilder {
StructureBuilder::new()
}
pub fn width(&self) -> u64 {
unsafe { BNGetStructureWidth(self.handle) }
}
pub fn structure_type(&self) -> StructureType {
unsafe { BNGetStructureType(self.handle) }
}
pub fn members(&self) -> Vec<StructureMember> {
unsafe {
let mut count = 0;
let members_raw_ptr: *mut BNStructureMember =
BNGetStructureMembers(self.handle, &mut count);
debug_assert!(!members_raw_ptr.is_null());
let members_raw = std::slice::from_raw_parts(members_raw_ptr, count);
let members = members_raw.iter().map(StructureMember::from_raw).collect();
BNFreeStructureMemberList(members_raw_ptr, count);
members
}
}
pub fn base_structures(&self) -> Vec<BaseStructure> {
let mut count = 0;
let bases_raw_ptr = unsafe { BNGetBaseStructuresForStructure(self.handle, &mut count) };
debug_assert!(!bases_raw_ptr.is_null());
let bases_raw = unsafe { std::slice::from_raw_parts(bases_raw_ptr, count) };
let bases = bases_raw.iter().map(BaseStructure::from_raw).collect();
unsafe { BNFreeBaseStructureList(bases_raw_ptr, count) };
bases
}
}
impl Debug for Structure {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Structure")
.field("width", &self.width())
.field("structure_type", &self.structure_type())
.field("base_structures", &self.base_structures())
.field("members", &self.members())
.finish()
}
}
unsafe impl RefCountable for Structure {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Self::ref_from_raw(BNNewStructureReference(handle.handle))
}
unsafe fn dec_ref(handle: &Self) {
BNFreeStructure(handle.handle);
}
}
impl ToOwned for Structure {
type Owned = Ref<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct StructureMember {
pub ty: Conf<Ref<Type>>,
pub name: String,
pub offset: u64,
pub access: MemberAccess,
pub scope: MemberScope,
}
impl StructureMember {
pub(crate) fn from_raw(value: &BNStructureMember) -> Self {
Self {
ty: Conf::new(
unsafe { Type::from_raw(value.type_) }.to_owned(),
value.typeConfidence,
),
name: raw_to_string(value.name as *mut _).unwrap(),
offset: value.offset,
access: value.access,
scope: value.scope,
}
}
pub(crate) fn from_owned_raw(value: BNStructureMember) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNStructureMember {
let bn_name = BnString::new(value.name);
BNStructureMember {
type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
name: BnString::into_raw(bn_name),
offset: value.offset,
typeConfidence: value.ty.confidence,
access: value.access,
scope: value.scope,
}
}
pub(crate) fn free_raw(value: BNStructureMember) {
let _ = unsafe { Type::ref_from_raw(value.type_) };
let _ = unsafe { BnString::from_raw(value.name) };
}
pub fn new(
ty: Conf<Ref<Type>>,
name: String,
offset: u64,
access: MemberAccess,
scope: MemberScope,
) -> Self {
Self {
ty,
name,
offset,
access,
scope,
}
}
}
impl CoreArrayProvider for StructureMember {
type Raw = BNStructureMember;
type Context = ();
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for StructureMember {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeStructureMemberList(raw, count)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
Self::from_raw(raw)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct InheritedStructureMember {
pub base: Ref<NamedTypeReference>,
pub base_offset: u64,
pub member: StructureMember,
pub member_index: usize,
}
impl InheritedStructureMember {
pub fn new(
base: Ref<NamedTypeReference>,
base_offset: u64,
member: StructureMember,
member_index: usize,
) -> Self {
Self {
base,
base_offset,
member,
member_index,
}
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct BaseStructure {
pub ty: Ref<NamedTypeReference>,
pub offset: u64,
pub width: u64,
}
impl BaseStructure {
pub(crate) fn from_raw(value: &BNBaseStructure) -> Self {
Self {
ty: unsafe { NamedTypeReference::from_raw(value.type_) }.to_owned(),
offset: value.offset,
width: value.width,
}
}
pub(crate) fn from_owned_raw(value: BNBaseStructure) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNBaseStructure {
BNBaseStructure {
type_: unsafe { Ref::into_raw(value.ty) }.handle,
offset: value.offset,
width: value.width,
}
}
pub(crate) fn into_owned_raw(value: &Self) -> BNBaseStructure {
BNBaseStructure {
type_: value.ty.handle,
offset: value.offset,
width: value.width,
}
}
pub(crate) fn free_raw(value: BNBaseStructure) {
let _ = unsafe { NamedTypeReference::ref_from_raw(value.type_) };
}
pub fn new(ty: Ref<NamedTypeReference>, offset: u64, width: u64) -> Self {
Self { ty, offset, width }
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct NamedTypeReference {
pub(crate) handle: *mut BNNamedTypeReference,
}
impl NamedTypeReference {
pub(crate) unsafe fn from_raw(handle: *mut BNNamedTypeReference) -> Self {
debug_assert!(!handle.is_null());
Self { handle }
}
pub(crate) unsafe fn ref_from_raw(handle: *mut BNNamedTypeReference) -> Ref<Self> {
debug_assert!(!handle.is_null());
Ref::new(Self { handle })
}
pub fn new<T: Into<QualifiedName>>(type_class: NamedTypeReferenceClass, name: T) -> Ref<Self> {
let mut raw_name = QualifiedName::into_raw(name.into());
let result = unsafe {
Self::ref_from_raw(BNCreateNamedType(
type_class,
std::ptr::null(),
&mut raw_name,
))
};
QualifiedName::free_raw(raw_name);
result
}
pub fn new_with_id<T: Into<QualifiedName>, S: BnStrCompatible>(
type_class: NamedTypeReferenceClass,
type_id: S,
name: T,
) -> Ref<Self> {
let type_id = type_id.into_bytes_with_nul();
let mut raw_name = QualifiedName::into_raw(name.into());
let result = unsafe {
Self::ref_from_raw(BNCreateNamedType(
type_class,
type_id.as_ref().as_ptr() as _,
&mut raw_name,
))
};
QualifiedName::free_raw(raw_name);
result
}
pub fn name(&self) -> QualifiedName {
let raw_name = unsafe { BNGetTypeReferenceName(self.handle) };
QualifiedName::from_owned_raw(raw_name)
}
pub fn id(&self) -> BnString {
unsafe { BnString::from_raw(BNGetTypeReferenceId(self.handle)) }
}
pub fn class(&self) -> NamedTypeReferenceClass {
unsafe { BNGetTypeReferenceClass(self.handle) }
}
fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet<BnString>) -> Option<Ref<Type>> {
let ty = bv.type_by_id(self.id())?;
match ty.type_class() {
TypeClass::NamedTypeReferenceClass => {
let ntr = ty.get_named_type_reference().unwrap();
match visited.insert(ntr.id()) {
true => ntr.target_helper(bv, visited),
false => {
log::error!("Can't get target for recursively defined type!");
None
}
}
}
_ => Some(ty),
}
}
pub fn target(&self, bv: &BinaryView) -> Option<Ref<Type>> {
self.target_helper(bv, &mut HashSet::new())
}
}
impl ToOwned for NamedTypeReference {
type Owned = Ref<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
unsafe impl RefCountable for NamedTypeReference {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Self::ref_from_raw(BNNewNamedTypeReference(handle.handle))
}
unsafe fn dec_ref(handle: &Self) {
BNFreeNamedTypeReference(handle.handle)
}
}
impl Debug for NamedTypeReference {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} (id: {})", self.name(), self.id())
}
}
#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
pub struct QualifiedName {
pub separator: String,
pub items: Vec<String>,
}
impl QualifiedName {
pub(crate) fn from_raw(value: &BNQualifiedName) -> Self {
let raw_names = unsafe { std::slice::from_raw_parts(value.name, value.nameCount) };
let items = raw_names
.iter()
.filter_map(|&raw_name| raw_to_string(raw_name as *const _))
.collect();
let separator = raw_to_string(value.join).unwrap();
Self { items, separator }
}
pub(crate) fn from_owned_raw(value: BNQualifiedName) -> Self {
let result = Self::from_raw(&value);
Self::free_raw(value);
result
}
pub fn into_raw(value: Self) -> BNQualifiedName {
let bn_join = BnString::new(&value.separator);
BNQualifiedName {
name: strings_to_string_list(&value.items),
join: BnString::into_raw(bn_join),
nameCount: value.items.len(),
}
}
pub(crate) fn free_raw(value: BNQualifiedName) {
unsafe { BNFreeString(value.join) };
unsafe { BNFreeStringList(value.name, value.nameCount) };
}
pub fn new(items: Vec<String>) -> Self {
Self::new_with_separator(items, "::".to_string())
}
pub fn new_with_separator(items: Vec<String>, separator: String) -> Self {
Self { items, separator }
}
pub fn with_item(&self, item: impl Into<String>) -> Self {
let mut items = self.items.clone();
items.push(item.into());
Self::new_with_separator(items, self.separator.clone())
}
pub fn push(&mut self, item: String) {
self.items.push(item);
}
pub fn pop(&mut self) -> Option<String> {
self.items.pop()
}
pub fn insert(&mut self, index: usize, item: String) {
if index <= self.items.len() {
self.items.insert(index, item);
}
}
pub fn split_last(&self) -> Option<(String, QualifiedName)> {
self.items.split_last().map(|(a, b)| {
(
a.to_owned(),
QualifiedName::new_with_separator(b.to_vec(), self.separator.clone()),
)
})
}
pub fn replace(&self, from: &str, to: &str) -> Self {
Self {
items: self
.items
.iter()
.map(|item| item.replace(from, to))
.collect(),
separator: self.separator.clone(),
}
}
pub fn last(&self) -> Option<&String> {
self.items.last()
}
pub fn last_mut(&mut self) -> Option<&mut String> {
self.items.last_mut()
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
impl From<String> for QualifiedName {
fn from(value: String) -> Self {
Self {
items: vec![value],
separator: String::from("::"),
}
}
}
impl From<&str> for QualifiedName {
fn from(value: &str) -> Self {
Self::from(value.to_string())
}
}
impl From<&String> for QualifiedName {
fn from(value: &String) -> Self {
Self::from(value.to_owned())
}
}
impl From<Cow<'_, str>> for QualifiedName {
fn from(value: Cow<'_, str>) -> Self {
Self::from(value.to_string())
}
}
impl From<Vec<String>> for QualifiedName {
fn from(value: Vec<String>) -> Self {
Self::new(value)
}
}
impl From<Vec<&str>> for QualifiedName {
fn from(value: Vec<&str>) -> Self {
value
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.into()
}
}
impl From<QualifiedName> for String {
fn from(value: QualifiedName) -> Self {
value.to_string()
}
}
impl Index<usize> for QualifiedName {
type Output = String;
fn index(&self, index: usize) -> &Self::Output {
&self.items[index]
}
}
impl IndexMut<usize> for QualifiedName {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.items[index]
}
}
impl Display for QualifiedName {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.items.join(&self.separator))
}
}
impl CoreArrayProvider for QualifiedName {
type Raw = BNQualifiedName;
type Context = ();
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for QualifiedName {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeTypeNameList(raw, count);
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
QualifiedName::from_raw(raw)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct QualifiedNameAndType {
pub name: QualifiedName,
pub ty: Ref<Type>,
}
impl QualifiedNameAndType {
pub(crate) fn from_raw(value: &BNQualifiedNameAndType) -> Self {
Self {
name: QualifiedName::from_raw(&value.name),
ty: unsafe { Type::from_raw(value.type_).to_owned() },
}
}
pub(crate) fn from_owned_raw(value: BNQualifiedNameAndType) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNQualifiedNameAndType {
BNQualifiedNameAndType {
name: QualifiedName::into_raw(value.name),
type_: unsafe { Ref::into_raw(value.ty).handle },
}
}
pub(crate) fn free_raw(value: BNQualifiedNameAndType) {
QualifiedName::free_raw(value.name);
let _ = unsafe { Type::ref_from_raw(value.type_) };
}
pub fn new(name: QualifiedName, ty: Ref<Type>) -> Self {
Self { name, ty }
}
}
impl<T> From<(T, Ref<Type>)> for QualifiedNameAndType
where
T: Into<QualifiedName>,
{
fn from(value: (T, Ref<Type>)) -> Self {
Self {
name: value.0.into(),
ty: value.1,
}
}
}
impl<T> From<(T, &Type)> for QualifiedNameAndType
where
T: Into<QualifiedName>,
{
fn from(value: (T, &Type)) -> Self {
let ty = value.1.to_owned();
Self {
name: value.0.into(),
ty,
}
}
}
impl CoreArrayProvider for QualifiedNameAndType {
type Raw = BNQualifiedNameAndType;
type Context = ();
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for QualifiedNameAndType {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeTypeAndNameList(raw, count);
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
QualifiedNameAndType::from_raw(raw)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct QualifiedNameTypeAndId {
pub name: QualifiedName,
pub ty: Ref<Type>,
pub id: String,
}
impl QualifiedNameTypeAndId {
pub(crate) fn from_raw(value: &BNQualifiedNameTypeAndId) -> Self {
Self {
name: QualifiedName::from_raw(&value.name),
ty: unsafe { Type::from_raw(value.type_) }.to_owned(),
id: raw_to_string(value.id).unwrap(),
}
}
pub(crate) fn from_owned_raw(value: BNQualifiedNameTypeAndId) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNQualifiedNameTypeAndId {
let bn_id = BnString::new(value.id);
BNQualifiedNameTypeAndId {
name: QualifiedName::into_raw(value.name),
id: BnString::into_raw(bn_id),
type_: unsafe { Ref::into_raw(value.ty) }.handle,
}
}
pub(crate) fn free_raw(value: BNQualifiedNameTypeAndId) {
QualifiedName::free_raw(value.name);
let _ = unsafe { Type::ref_from_raw(value.type_) };
let _ = unsafe { BnString::from_raw(value.id) };
}
}
impl CoreArrayProvider for QualifiedNameTypeAndId {
type Raw = BNQualifiedNameTypeAndId;
type Context = ();
type Wrapped<'a> = QualifiedNameTypeAndId;
}
unsafe impl CoreArrayProviderInner for QualifiedNameTypeAndId {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeTypeIdList(raw, count);
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
QualifiedNameTypeAndId::from_raw(raw)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct NameAndType {
pub name: String,
pub ty: Conf<Ref<Type>>,
}
impl NameAndType {
pub(crate) fn from_raw(value: &BNNameAndType) -> Self {
Self {
name: raw_to_string(value.name as *mut _).unwrap(),
ty: Conf::new(
unsafe { Type::from_raw(value.type_).to_owned() },
value.typeConfidence,
),
}
}
pub(crate) fn from_owned_raw(value: BNNameAndType) -> Self {
let owned = Self::from_raw(&value);
Self::free_raw(value);
owned
}
pub(crate) fn into_raw(value: Self) -> BNNameAndType {
let bn_name = BnString::new(value.name);
BNNameAndType {
name: BnString::into_raw(bn_name),
type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
typeConfidence: value.ty.confidence,
}
}
pub(crate) fn free_raw(value: BNNameAndType) {
let _ = unsafe { BnString::from_raw(value.name) };
let _ = unsafe { Type::ref_from_raw(value.type_) };
}
pub fn new(name: impl Into<String>, ty: Conf<Ref<Type>>) -> Self {
Self {
name: name.into(),
ty,
}
}
}
impl CoreArrayProvider for NameAndType {
type Raw = BNNameAndType;
type Context = ();
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for NameAndType {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeNameAndTypeList(raw, count);
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
NameAndType::from_raw(raw)
}
}