summaryrefslogtreecommitdiff
path: root/rust/src/variable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/variable.rs')
-rw-r--r--rust/src/variable.rs910
1 files changed, 910 insertions, 0 deletions
diff --git a/rust/src/variable.rs b/rust/src/variable.rs
new file mode 100644
index 00000000..260e12d8
--- /dev/null
+++ b/rust/src/variable.rs
@@ -0,0 +1,910 @@
+#![allow(unused)]
+
+use crate::confidence::Conf;
+use crate::function::{Function, Location};
+use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
+use crate::string::{raw_to_string, BnString};
+use crate::types::Type;
+use binaryninjacore_sys::{
+ BNDataVariable, BNDataVariableAndName, BNFreeDataVariableAndName, BNFreeDataVariables,
+ BNFreeILInstructionList, BNFreeIndirectBranchList, BNFreeMergedVariableList,
+ BNFreePossibleValueSet, BNFreeStackVariableReferenceList, BNFreeUserVariableValues,
+ BNFreeVariableList, BNFreeVariableNameAndTypeList, BNFromVariableIdentifier,
+ BNIndirectBranchInfo, BNLookupTableEntry, BNMergedVariable, BNPossibleValueSet,
+ BNRegisterValue, BNRegisterValueType, BNStackVariableReference, BNToVariableIdentifier,
+ BNUserVariableValue, BNValueRange, BNVariable, BNVariableNameAndType, BNVariableSourceType,
+};
+use std::collections::HashSet;
+
+pub type VariableSourceType = BNVariableSourceType;
+pub type RegisterValueType = BNRegisterValueType;
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct DataVariable {
+ pub address: u64,
+ pub ty: Conf<Ref<Type>>,
+ pub auto_discovered: bool,
+}
+
+impl DataVariable {
+ pub(crate) fn from_raw(value: &BNDataVariable) -> Self {
+ Self {
+ address: value.address,
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_).to_owned() },
+ value.typeConfidence,
+ ),
+ auto_discovered: value.autoDiscovered,
+ }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNDataVariable) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNDataVariable {
+ BNDataVariable {
+ address: value.address,
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ autoDiscovered: value.auto_discovered,
+ typeConfidence: value.ty.confidence,
+ }
+ }
+
+ pub(crate) fn into_owned_raw(value: &Self) -> BNDataVariable {
+ BNDataVariable {
+ address: value.address,
+ type_: value.ty.contents.handle,
+ autoDiscovered: value.auto_discovered,
+ typeConfidence: value.ty.confidence,
+ }
+ }
+
+ pub(crate) fn free_raw(value: BNDataVariable) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ }
+
+ pub fn new(address: u64, ty: Conf<Ref<Type>>, auto_discovered: bool) -> Self {
+ Self {
+ address,
+ ty,
+ auto_discovered,
+ }
+ }
+}
+
+impl CoreArrayProvider for DataVariable {
+ type Raw = BNDataVariable;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for DataVariable {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeDataVariables(raw, count);
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ DataVariable::from_raw(raw)
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct NamedDataVariableWithType {
+ pub address: u64,
+ pub ty: Conf<Ref<Type>>,
+ pub name: String,
+ pub auto_discovered: bool,
+}
+
+impl NamedDataVariableWithType {
+ pub(crate) fn from_raw(value: &BNDataVariableAndName) -> Self {
+ Self {
+ address: value.address,
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_).to_owned() },
+ value.typeConfidence,
+ ),
+ // TODO: I dislike using this function here.
+ name: raw_to_string(value.name as *mut _).unwrap(),
+ auto_discovered: value.autoDiscovered,
+ }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNDataVariableAndName) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
+ }
+
+ pub(crate) unsafe fn from_ref_raw(value: *mut BNDataVariableAndName) -> Self {
+ let owned = Self::from_raw(&*value);
+ Self::free_ref_raw(value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNDataVariableAndName {
+ let bn_name = BnString::new(value.name);
+ BNDataVariableAndName {
+ address: value.address,
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ name: BnString::into_raw(bn_name),
+ autoDiscovered: value.auto_discovered,
+ typeConfidence: value.ty.confidence,
+ }
+ }
+
+ pub(crate) fn free_ref_raw(value: *mut BNDataVariableAndName) {
+ unsafe { BNFreeDataVariableAndName(value) }
+ }
+
+ pub(crate) fn free_raw(value: BNDataVariableAndName) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ let _ = unsafe { BnString::from_raw(value.name) };
+ }
+
+ pub fn new(address: u64, ty: Conf<Ref<Type>>, name: String, auto_discovered: bool) -> Self {
+ Self {
+ address,
+ ty,
+ name,
+ auto_discovered,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct NamedVariableWithType {
+ pub variable: Variable,
+ pub ty: Conf<Ref<Type>>,
+ pub name: String,
+ pub auto_defined: bool,
+}
+
+impl NamedVariableWithType {
+ pub(crate) fn from_raw(value: &BNVariableNameAndType) -> Self {
+ Self {
+ variable: value.var.into(),
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_) }.to_owned(),
+ value.typeConfidence,
+ ),
+ // TODO: I dislike using this function here.
+ name: raw_to_string(value.name as *mut _).unwrap(),
+ auto_defined: value.autoDefined,
+ }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNVariableNameAndType) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNVariableNameAndType {
+ let bn_name = BnString::new(value.name);
+ BNVariableNameAndType {
+ var: value.variable.into(),
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ name: BnString::into_raw(bn_name),
+ autoDefined: value.auto_defined,
+ typeConfidence: value.ty.confidence,
+ }
+ }
+
+ pub(crate) fn free_raw(value: BNVariableNameAndType) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ let _ = unsafe { BnString::from_raw(value.name) };
+ }
+
+ pub fn new(variable: Variable, ty: Conf<Ref<Type>>, name: String, auto_defined: bool) -> Self {
+ Self {
+ variable,
+ ty,
+ name,
+ auto_defined,
+ }
+ }
+}
+
+impl CoreArrayProvider for NamedVariableWithType {
+ type Raw = BNVariableNameAndType;
+ type Context = ();
+ type Wrapped<'a> = NamedVariableWithType;
+}
+
+unsafe impl CoreArrayProviderInner for NamedVariableWithType {
+ 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) -> Self::Wrapped<'a> {
+ Self::from_raw(raw)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct UserVariableValue {
+ pub variable: Variable,
+ pub def_site: Location,
+ pub value: PossibleValueSet,
+}
+
+impl UserVariableValue {
+ pub(crate) fn from_raw(value: &BNUserVariableValue) -> Self {
+ Self {
+ variable: value.var.into(),
+ def_site: value.defSite.into(),
+ value: PossibleValueSet::from_raw(&value.value),
+ }
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNUserVariableValue {
+ BNUserVariableValue {
+ var: value.variable.into(),
+ defSite: value.def_site.into(),
+ value: PossibleValueSet::into_raw(value.value),
+ }
+ }
+}
+
+impl CoreArrayProvider for UserVariableValue {
+ type Raw = BNUserVariableValue;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for UserVariableValue {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeUserVariableValues(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ UserVariableValue::from_raw(raw)
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct StackVariableReference {
+ source_operand: u32,
+ pub variable_type: Conf<Ref<Type>>,
+ pub name: String,
+ pub variable: Variable,
+ pub offset: i64,
+ pub size: usize,
+}
+
+impl StackVariableReference {
+ pub(crate) fn from_raw(value: &BNStackVariableReference) -> Self {
+ Self {
+ source_operand: value.sourceOperand,
+ variable_type: Conf::new(
+ unsafe { Type::from_raw(value.type_) }.to_owned(),
+ value.typeConfidence,
+ ),
+ // TODO: I dislike using this function here.
+ name: raw_to_string(value.name).unwrap(),
+ // TODO: It might be beneficial to newtype the identifier as VariableIdentifier.
+ variable: Variable::from_identifier(value.varIdentifier),
+ offset: value.referencedOffset,
+ size: value.size,
+ }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNStackVariableReference) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_raw(value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNStackVariableReference {
+ let bn_name = BnString::new(value.name);
+ BNStackVariableReference {
+ sourceOperand: value.source_operand,
+ typeConfidence: value.variable_type.confidence,
+ type_: unsafe { Ref::into_raw(value.variable_type.contents) }.handle,
+ name: BnString::into_raw(bn_name),
+ varIdentifier: value.variable.to_identifier(),
+ referencedOffset: value.offset,
+ size: value.size,
+ }
+ }
+
+ pub(crate) fn free_raw(value: BNStackVariableReference) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ let _ = unsafe { BnString::from_raw(value.name) };
+ }
+}
+
+impl CoreArrayProvider for StackVariableReference {
+ type Raw = BNStackVariableReference;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for StackVariableReference {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeStackVariableReferenceList(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ StackVariableReference::from_raw(raw)
+ }
+}
+
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+pub struct SSAVariable {
+ pub variable: Variable,
+ pub version: usize,
+}
+
+impl SSAVariable {
+ pub fn new(variable: Variable, version: usize) -> Self {
+ Self { variable, version }
+ }
+}
+
+impl CoreArrayProvider for SSAVariable {
+ type Raw = usize;
+ type Context = Variable;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for SSAVariable {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeILInstructionList(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ SSAVariable::new(*context, *raw)
+ }
+}
+
+/// Variables exist within functions at Medium Level IL or higher.
+///
+/// As such, they are to be used within the context of a [`Function`].
+/// See [`Function::variable_name`] as an example of how to interact with variables.
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Variable {
+ pub ty: VariableSourceType,
+ // TODO: VariableIndex type?
+ pub index: u32,
+ // TODO: Type this to `VariableStorage`
+ pub storage: i64,
+}
+
+impl Variable {
+ pub fn new(ty: VariableSourceType, index: u32, storage: i64) -> Self {
+ Self { ty, index, storage }
+ }
+
+ // TODO: Retype this...
+ // TODO: Add VariableIdentifier
+ // TODO: StackVariableReference has a varIdentifier, i think thats really it.
+ pub fn from_identifier(ident: u64) -> Self {
+ unsafe { BNFromVariableIdentifier(ident) }.into()
+ }
+
+ pub fn to_identifier(&self) -> u64 {
+ let raw = BNVariable::from(*self);
+ unsafe { BNToVariableIdentifier(&raw) }
+ }
+}
+
+impl From<BNVariable> for Variable {
+ fn from(value: BNVariable) -> Self {
+ Self {
+ ty: value.type_,
+ index: value.index,
+ storage: value.storage,
+ }
+ }
+}
+
+impl From<&BNVariable> for Variable {
+ fn from(value: &BNVariable) -> Self {
+ Self::from(*value)
+ }
+}
+
+impl From<Variable> for BNVariable {
+ fn from(value: Variable) -> Self {
+ Self {
+ type_: value.ty,
+ index: value.index,
+ storage: value.storage,
+ }
+ }
+}
+
+impl From<&Variable> for BNVariable {
+ fn from(value: &Variable) -> Self {
+ BNVariable::from(*value)
+ }
+}
+
+impl CoreArrayProvider for Variable {
+ type Raw = BNVariable;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for Variable {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeVariableList(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Variable::from(raw)
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct MergedVariable {
+ pub target: Variable,
+ pub sources: Vec<Variable>,
+}
+
+impl MergedVariable {
+ pub(crate) fn from_raw(value: &BNMergedVariable) -> Self {
+ let raw_sources = unsafe { std::slice::from_raw_parts(value.sources, value.sourceCount) };
+ Self {
+ target: value.target.into(),
+ sources: raw_sources.iter().map(Into::into).collect(),
+ }
+ }
+
+ // TODO: If we want from_owned_raw/free_raw/into_raw we need a way to allocate sources.
+}
+
+impl CoreArrayProvider for MergedVariable {
+ type Raw = BNMergedVariable;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for MergedVariable {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeMergedVariableList(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Self::from_raw(raw)
+ }
+}
+
+// TODO: This is used in MLIL and HLIL, this really should exist in each of those.
+#[derive(Clone, Debug, Hash, Eq, PartialEq)]
+pub struct ConstantData {
+ // TODO: We really do not want to store a ref to function here.
+ pub function: Ref<Function>,
+ pub value: RegisterValue,
+}
+
+impl ConstantData {
+ pub fn new(function: Ref<Function>, value: RegisterValue) -> Self {
+ Self { function, value }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+pub struct RegisterValue {
+ pub state: RegisterValueType,
+ // TODO: This value can be anything. Make `T`
+ pub value: i64,
+ pub offset: i64,
+ pub size: usize,
+}
+
+impl RegisterValue {
+ pub fn new(state: RegisterValueType, value: i64, offset: i64, size: usize) -> Self {
+ Self {
+ state,
+ value,
+ offset,
+ size,
+ }
+ }
+}
+
+impl From<BNRegisterValue> for RegisterValue {
+ fn from(value: BNRegisterValue) -> Self {
+ Self {
+ state: value.state,
+ value: value.value,
+ offset: value.offset,
+ size: value.size,
+ }
+ }
+}
+
+impl From<RegisterValue> for BNRegisterValue {
+ fn from(value: RegisterValue) -> Self {
+ Self {
+ state: value.state,
+ value: value.value,
+ offset: value.offset,
+ size: value.size,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct ValueRange<T> {
+ pub start: T,
+ pub end: T,
+ pub step: u64,
+}
+
+impl From<BNValueRange> for ValueRange<u64> {
+ fn from(value: BNValueRange) -> Self {
+ Self {
+ start: value.start,
+ end: value.end,
+ step: value.step,
+ }
+ }
+}
+
+impl From<ValueRange<u64>> for BNValueRange {
+ fn from(value: ValueRange<u64>) -> Self {
+ Self {
+ start: value.start,
+ end: value.end,
+ step: value.step,
+ }
+ }
+}
+
+impl From<BNValueRange> for ValueRange<i64> {
+ fn from(value: BNValueRange) -> Self {
+ Self {
+ start: value.start as i64,
+ end: value.end as i64,
+ step: value.step,
+ }
+ }
+}
+
+impl From<ValueRange<i64>> for BNValueRange {
+ fn from(value: ValueRange<i64>) -> Self {
+ Self {
+ start: value.start as u64,
+ end: value.end as u64,
+ step: value.step,
+ }
+ }
+}
+
+// TODO: Document where its used and why it exists.
+// TODO: What if we are looking up u64?
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct LookupTableEntry {
+ /// The set of integers that correspond with [`Self::to`].
+ from: HashSet<i64>,
+ /// The associated "mapped" value.
+ to: i64,
+}
+
+impl LookupTableEntry {
+ pub(crate) fn from_raw(value: &BNLookupTableEntry) -> Self {
+ let from_values = unsafe { std::slice::from_raw_parts(value.fromValues, value.fromCount) };
+ Self {
+ // TODO: Better way to construct HashSet<i64>?
+ from: HashSet::from_iter(from_values.iter().copied()),
+ to: value.toValue,
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum PossibleValueSet {
+ UndeterminedValue,
+ EntryValue {
+ // TODO: This is actually the BNVariable storage.
+ // TODO: Type this to `VariableStorage` or something.
+ reg: i64,
+ },
+ ConstantValue {
+ // TODO: Make this T
+ // TODO: This can be really anything (signed, unsigned or even a float).
+ value: i64,
+ },
+ ConstantPointerValue {
+ // TODO: Shouldn't this be u64?
+ value: i64,
+ },
+ ExternalPointerValue {
+ // TODO: Shouldn't this be u64?
+ value: i64,
+ offset: i64,
+ },
+ StackFrameOffset {
+ value: i64,
+ },
+ ReturnAddressValue,
+ ImportedAddressValue,
+ SignedRangeValue {
+ value: i64,
+ ranges: Vec<ValueRange<i64>>,
+ },
+ UnsignedRangeValue {
+ value: i64,
+ ranges: Vec<ValueRange<u64>>,
+ },
+ LookupTableValue {
+ table: Vec<LookupTableEntry>,
+ },
+ InSetOfValues {
+ values: HashSet<i64>,
+ },
+ NotInSetOfValues {
+ values: HashSet<i64>,
+ },
+ // TODO: Can you even get _just_ a constant data value?
+ ConstantDataValue {
+ value: i64,
+ size: usize,
+ },
+ ConstantDataZeroExtendValue {
+ // TODO: Zero extend should be u64?
+ value: i64,
+ size: usize,
+ },
+ ConstantDataSignExtendValue {
+ value: i64,
+ size: usize,
+ },
+ ConstantDataAggregateValue {
+ // WTF is aggregate??
+ value: i64,
+ size: usize,
+ },
+}
+
+impl PossibleValueSet {
+ pub(crate) fn from_raw(value: &BNPossibleValueSet) -> Self {
+ match value.state {
+ RegisterValueType::UndeterminedValue => Self::UndeterminedValue,
+ RegisterValueType::EntryValue => Self::EntryValue { reg: value.value },
+ RegisterValueType::ConstantValue => Self::ConstantValue { value: value.value },
+ RegisterValueType::ConstantPointerValue => {
+ Self::ConstantPointerValue { value: value.value }
+ }
+ RegisterValueType::ExternalPointerValue => Self::ExternalPointerValue {
+ value: value.value,
+ offset: value.offset,
+ },
+ RegisterValueType::StackFrameOffset => Self::StackFrameOffset { value: value.value },
+ RegisterValueType::ReturnAddressValue => Self::ReturnAddressValue,
+ RegisterValueType::ImportedAddressValue => Self::ImportedAddressValue,
+ RegisterValueType::SignedRangeValue => {
+ let raw_ranges = unsafe { std::slice::from_raw_parts(value.ranges, value.count) };
+ Self::SignedRangeValue {
+ value: value.value,
+ ranges: raw_ranges.iter().map(|&r| r.into()).collect(),
+ }
+ }
+ RegisterValueType::UnsignedRangeValue => {
+ let raw_ranges = unsafe { std::slice::from_raw_parts(value.ranges, value.count) };
+ Self::UnsignedRangeValue {
+ value: value.value,
+ ranges: raw_ranges.iter().map(|&r| r.into()).collect(),
+ }
+ }
+ RegisterValueType::LookupTableValue => {
+ let raw_entries = unsafe { std::slice::from_raw_parts(value.table, value.count) };
+ Self::LookupTableValue {
+ table: raw_entries.iter().map(LookupTableEntry::from_raw).collect(),
+ }
+ }
+ RegisterValueType::InSetOfValues => {
+ let raw_values = unsafe { std::slice::from_raw_parts(value.valueSet, value.count) };
+ Self::InSetOfValues {
+ values: raw_values.iter().copied().collect(),
+ }
+ }
+ RegisterValueType::NotInSetOfValues => {
+ let raw_values = unsafe { std::slice::from_raw_parts(value.valueSet, value.count) };
+ Self::NotInSetOfValues {
+ values: raw_values.iter().copied().collect(),
+ }
+ }
+ RegisterValueType::ConstantDataValue => Self::ConstantDataValue {
+ value: value.value,
+ size: value.size,
+ },
+ RegisterValueType::ConstantDataZeroExtendValue => Self::ConstantDataZeroExtendValue {
+ value: value.value,
+ size: value.size,
+ },
+ RegisterValueType::ConstantDataSignExtendValue => Self::ConstantDataSignExtendValue {
+ value: value.value,
+ size: value.size,
+ },
+ RegisterValueType::ConstantDataAggregateValue => Self::ConstantDataAggregateValue {
+ value: value.value,
+ size: value.size,
+ },
+ }
+ }
+
+ /// Take ownership over an "owned" core allocated value. Do not call this for a rust allocated value.
+ pub(crate) fn from_owned_raw(mut value: BNPossibleValueSet) -> Self {
+ let owned = Self::from_raw(&value);
+ // TODO: This entire function is a little wonky.
+ Self::free_raw(&mut value);
+ owned
+ }
+
+ pub(crate) fn into_raw(value: Self) -> BNPossibleValueSet {
+ let mut raw = BNPossibleValueSet {
+ state: value.value_type(),
+ ..Default::default()
+ };
+ match value {
+ PossibleValueSet::UndeterminedValue => {}
+ PossibleValueSet::EntryValue { reg } => {
+ raw.value = reg;
+ }
+ PossibleValueSet::ConstantValue { value } => {
+ raw.value = value;
+ }
+ PossibleValueSet::ConstantPointerValue { value } => {
+ raw.value = value;
+ }
+ PossibleValueSet::ExternalPointerValue { value, offset } => {
+ raw.value = value;
+ raw.offset = offset;
+ }
+ PossibleValueSet::StackFrameOffset { value } => {
+ raw.value = value;
+ }
+ PossibleValueSet::ReturnAddressValue => {}
+ PossibleValueSet::ImportedAddressValue => {}
+ PossibleValueSet::SignedRangeValue { value, ranges } => {
+ raw.value = value;
+ // TODO: raw.ranges
+ // TODO: requires core allocation and freeing.
+ // TODO: See `BNFreePossibleValueSet` for why this sucks.
+ }
+ PossibleValueSet::UnsignedRangeValue { value, ranges } => {
+ raw.value = value;
+ // TODO: raw.ranges
+ // TODO: requires core allocation and freeing.
+ // TODO: See `BNFreePossibleValueSet` for why this sucks.
+ }
+ PossibleValueSet::LookupTableValue { table } => {
+ // TODO: raw.table
+ // TODO: requires core allocation and freeing.
+ // TODO: See `BNFreePossibleValueSet` for why this sucks.
+ }
+ PossibleValueSet::InSetOfValues { values } => {
+ // TODO: raw.valueSet
+ // TODO: requires core allocation and freeing.
+ // TODO: See `BNFreePossibleValueSet` for why this sucks.
+ }
+ PossibleValueSet::NotInSetOfValues { values } => {
+ // TODO: raw.valueSet
+ // TODO: requires core allocation and freeing.
+ // TODO: See `BNFreePossibleValueSet` for why this sucks.
+ }
+ PossibleValueSet::ConstantDataValue { value, size } => {
+ raw.value = value;
+ raw.size = size;
+ }
+ PossibleValueSet::ConstantDataZeroExtendValue { value, size } => {
+ raw.value = value;
+ raw.size = size;
+ }
+ PossibleValueSet::ConstantDataSignExtendValue { value, size } => {
+ raw.value = value;
+ raw.size = size;
+ }
+ PossibleValueSet::ConstantDataAggregateValue { value, size } => {
+ raw.value = value;
+ raw.size = size;
+ }
+ };
+ raw
+ }
+
+ /// Free a CORE ALLOCATED possible value set. Do not use this with [Self::into_raw] values.
+ pub(crate) fn free_raw(value: &mut BNPossibleValueSet) {
+ unsafe { BNFreePossibleValueSet(value) }
+ }
+
+ /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
+ pub(crate) fn free_owned_raw(value: BNPossibleValueSet) {
+ // TODO: Once we fill out allocation of the possible value set then we should fill this out as well.
+ }
+
+ pub fn value_type(&self) -> RegisterValueType {
+ match self {
+ PossibleValueSet::UndeterminedValue => RegisterValueType::UndeterminedValue,
+ PossibleValueSet::EntryValue { .. } => RegisterValueType::EntryValue,
+ PossibleValueSet::ConstantValue { .. } => RegisterValueType::ConstantValue,
+ PossibleValueSet::ConstantPointerValue { .. } => {
+ RegisterValueType::ConstantPointerValue
+ }
+ PossibleValueSet::ExternalPointerValue { .. } => {
+ RegisterValueType::ExternalPointerValue
+ }
+ PossibleValueSet::StackFrameOffset { .. } => RegisterValueType::StackFrameOffset,
+ PossibleValueSet::ReturnAddressValue => RegisterValueType::ReturnAddressValue,
+ PossibleValueSet::ImportedAddressValue => RegisterValueType::ImportedAddressValue,
+ PossibleValueSet::SignedRangeValue { .. } => RegisterValueType::SignedRangeValue,
+ PossibleValueSet::UnsignedRangeValue { .. } => RegisterValueType::UnsignedRangeValue,
+ PossibleValueSet::LookupTableValue { .. } => RegisterValueType::LookupTableValue,
+ PossibleValueSet::InSetOfValues { .. } => RegisterValueType::InSetOfValues,
+ PossibleValueSet::NotInSetOfValues { .. } => RegisterValueType::NotInSetOfValues,
+ PossibleValueSet::ConstantDataValue { .. } => RegisterValueType::ConstantDataValue,
+ PossibleValueSet::ConstantDataZeroExtendValue { .. } => {
+ RegisterValueType::ConstantDataZeroExtendValue
+ }
+ PossibleValueSet::ConstantDataSignExtendValue { .. } => {
+ RegisterValueType::ConstantDataSignExtendValue
+ }
+ PossibleValueSet::ConstantDataAggregateValue { .. } => {
+ RegisterValueType::ConstantDataAggregateValue
+ }
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct IndirectBranchInfo {
+ pub source: Location,
+ pub dest: Location,
+ pub auto_defined: bool,
+}
+
+impl From<BNIndirectBranchInfo> for IndirectBranchInfo {
+ fn from(value: BNIndirectBranchInfo) -> Self {
+ Self {
+ source: Location::from_raw(value.sourceAddr, value.sourceArch),
+ dest: Location::from_raw(value.destAddr, value.destArch),
+ auto_defined: value.autoDefined,
+ }
+ }
+}
+
+impl From<IndirectBranchInfo> for BNIndirectBranchInfo {
+ fn from(value: IndirectBranchInfo) -> Self {
+ let source_arch = value
+ .source
+ .arch
+ .map(|a| a.handle)
+ .unwrap_or(std::ptr::null_mut());
+ let dest_arch = value
+ .source
+ .arch
+ .map(|a| a.handle)
+ .unwrap_or(std::ptr::null_mut());
+ Self {
+ sourceArch: source_arch,
+ sourceAddr: value.source.addr,
+ destArch: dest_arch,
+ destAddr: value.dest.addr,
+ autoDefined: value.auto_defined,
+ }
+ }
+}
+
+impl CoreArrayProvider for IndirectBranchInfo {
+ type Raw = BNIndirectBranchInfo;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for IndirectBranchInfo {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeIndirectBranchList(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Self::from(*raw)
+ }
+}