binaryninja/
variable.rs

1#![allow(unused)]
2
3use crate::architecture::{Architecture, CoreArchitecture, CoreRegister, RegisterId};
4use crate::confidence::Conf;
5use crate::function::{Function, Location};
6use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
7use crate::string::{raw_to_string, BnString};
8use crate::types::Type;
9use binaryninjacore_sys::{
10    BNDataVariable, BNDataVariableAndName, BNFreeDataVariableAndName, BNFreeDataVariables,
11    BNFreeILInstructionList, BNFreeIndirectBranchList, BNFreeMergedVariableList,
12    BNFreePossibleValueSet, BNFreeStackVariableReferenceList, BNFreeUserVariableValues,
13    BNFreeVariableList, BNFreeVariableNameAndTypeList, BNFromVariableIdentifier,
14    BNIndirectBranchInfo, BNLookupTableEntry, BNMergedVariable, BNPossibleValueSet,
15    BNRegisterValue, BNRegisterValueType, BNStackVariableReference, BNToVariableIdentifier,
16    BNTypeWithConfidence, BNUserVariableValue, BNValueRange, BNVariable, BNVariableNameAndType,
17    BNVariableSourceType,
18};
19use std::collections::HashSet;
20
21pub type VariableSourceType = BNVariableSourceType;
22pub type RegisterValueType = BNRegisterValueType;
23
24#[derive(Debug, Clone, Hash, PartialEq, Eq)]
25pub struct DataVariable {
26    pub address: u64,
27    pub ty: Conf<Ref<Type>>,
28    pub auto_discovered: bool,
29}
30
31impl DataVariable {
32    pub(crate) fn from_raw(value: &BNDataVariable) -> Self {
33        Self {
34            address: value.address,
35            ty: Conf::new(
36                unsafe { Type::from_raw(value.type_).to_owned() },
37                value.typeConfidence,
38            ),
39            auto_discovered: value.autoDiscovered,
40        }
41    }
42
43    pub(crate) fn from_owned_raw(value: BNDataVariable) -> Self {
44        let owned = Self::from_raw(&value);
45        Self::free_raw(value);
46        owned
47    }
48
49    pub(crate) fn into_raw(value: Self) -> BNDataVariable {
50        BNDataVariable {
51            address: value.address,
52            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
53            autoDiscovered: value.auto_discovered,
54            typeConfidence: value.ty.confidence,
55        }
56    }
57
58    pub(crate) fn into_owned_raw(value: &Self) -> BNDataVariable {
59        BNDataVariable {
60            address: value.address,
61            type_: value.ty.contents.handle,
62            autoDiscovered: value.auto_discovered,
63            typeConfidence: value.ty.confidence,
64        }
65    }
66
67    pub(crate) fn free_raw(value: BNDataVariable) {
68        let _ = unsafe { Type::ref_from_raw(value.type_) };
69    }
70
71    pub fn new(address: u64, ty: Conf<Ref<Type>>, auto_discovered: bool) -> Self {
72        Self {
73            address,
74            ty,
75            auto_discovered,
76        }
77    }
78}
79
80impl CoreArrayProvider for DataVariable {
81    type Raw = BNDataVariable;
82    type Context = ();
83    type Wrapped<'a> = Self;
84}
85
86unsafe impl CoreArrayProviderInner for DataVariable {
87    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
88        BNFreeDataVariables(raw, count);
89    }
90
91    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
92        DataVariable::from_raw(raw)
93    }
94}
95
96#[derive(Debug, Clone, Hash, PartialEq, Eq)]
97pub struct NamedDataVariableWithType {
98    pub address: u64,
99    pub ty: Conf<Ref<Type>>,
100    pub name: String,
101    pub auto_discovered: bool,
102}
103
104impl NamedDataVariableWithType {
105    pub(crate) fn from_raw(value: &BNDataVariableAndName) -> Self {
106        Self {
107            address: value.address,
108            ty: Conf::new(
109                unsafe { Type::from_raw(value.type_).to_owned() },
110                value.typeConfidence,
111            ),
112            // TODO: I dislike using this function here.
113            name: raw_to_string(value.name as *mut _).unwrap(),
114            auto_discovered: value.autoDiscovered,
115        }
116    }
117
118    pub(crate) fn from_owned_raw(value: BNDataVariableAndName) -> Self {
119        let owned = Self::from_raw(&value);
120        Self::free_raw(value);
121        owned
122    }
123
124    pub(crate) fn into_raw(value: Self) -> BNDataVariableAndName {
125        let bn_name = BnString::new(value.name);
126        BNDataVariableAndName {
127            address: value.address,
128            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
129            name: BnString::into_raw(bn_name),
130            autoDiscovered: value.auto_discovered,
131            typeConfidence: value.ty.confidence,
132        }
133    }
134
135    pub(crate) fn free_raw(value: BNDataVariableAndName) {
136        let _ = unsafe { Type::ref_from_raw(value.type_) };
137        let _ = unsafe { BnString::from_raw(value.name) };
138    }
139
140    pub fn new(address: u64, ty: Conf<Ref<Type>>, name: String, auto_discovered: bool) -> Self {
141        Self {
142            address,
143            ty,
144            name,
145            auto_discovered,
146        }
147    }
148}
149
150#[derive(Debug, Clone, Hash, PartialEq, Eq)]
151pub struct NamedVariableWithType {
152    pub variable: Variable,
153    pub ty: Conf<Ref<Type>>,
154    pub name: String,
155    pub auto_defined: bool,
156}
157
158impl NamedVariableWithType {
159    pub(crate) fn from_raw(value: &BNVariableNameAndType) -> Self {
160        Self {
161            variable: value.var.into(),
162            ty: Conf::new(
163                unsafe { Type::from_raw(value.type_) }.to_owned(),
164                value.typeConfidence,
165            ),
166            // TODO: I dislike using this function here.
167            name: raw_to_string(value.name as *mut _).unwrap(),
168            auto_defined: value.autoDefined,
169        }
170    }
171
172    pub(crate) fn from_owned_raw(value: BNVariableNameAndType) -> Self {
173        let owned = Self::from_raw(&value);
174        Self::free_raw(value);
175        owned
176    }
177
178    pub(crate) fn into_raw(value: Self) -> BNVariableNameAndType {
179        let bn_name = BnString::new(value.name);
180        BNVariableNameAndType {
181            var: value.variable.into(),
182            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
183            name: BnString::into_raw(bn_name),
184            autoDefined: value.auto_defined,
185            typeConfidence: value.ty.confidence,
186        }
187    }
188
189    pub(crate) fn free_raw(value: BNVariableNameAndType) {
190        let _ = unsafe { Type::ref_from_raw(value.type_) };
191        unsafe { BnString::free_raw(value.name) };
192    }
193
194    pub fn new(variable: Variable, ty: Conf<Ref<Type>>, name: String, auto_defined: bool) -> Self {
195        Self {
196            variable,
197            ty,
198            name,
199            auto_defined,
200        }
201    }
202}
203
204impl CoreArrayProvider for NamedVariableWithType {
205    type Raw = BNVariableNameAndType;
206    type Context = ();
207    type Wrapped<'a> = NamedVariableWithType;
208}
209
210unsafe impl CoreArrayProviderInner for NamedVariableWithType {
211    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
212        BNFreeVariableNameAndTypeList(raw, count)
213    }
214
215    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
216        Self::from_raw(raw)
217    }
218}
219
220#[derive(Debug, Clone, PartialEq, Eq)]
221pub struct UserVariableValue {
222    pub variable: Variable,
223    pub def_site: Location,
224    pub after: bool,
225    pub value: PossibleValueSet,
226}
227
228impl UserVariableValue {
229    pub(crate) fn from_raw(value: &BNUserVariableValue) -> Self {
230        Self {
231            variable: value.var.into(),
232            def_site: value.defSite.into(),
233            after: value.after,
234            value: PossibleValueSet::from_raw(&value.value),
235        }
236    }
237
238    pub(crate) fn into_raw(value: Self) -> BNUserVariableValue {
239        BNUserVariableValue {
240            var: value.variable.into(),
241            defSite: value.def_site.into(),
242            after: value.after,
243            // TODO: This returns a rust allocated value, we should at some point provide allocators for the
244            // TODO: internal state of BNPossibleValueSet, so we can store rust created object in core objects.
245            value: PossibleValueSet::into_rust_raw(value.value),
246        }
247    }
248}
249
250impl CoreArrayProvider for UserVariableValue {
251    type Raw = BNUserVariableValue;
252    type Context = ();
253    type Wrapped<'a> = Self;
254}
255
256unsafe impl CoreArrayProviderInner for UserVariableValue {
257    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
258        BNFreeUserVariableValues(raw)
259    }
260
261    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
262        UserVariableValue::from_raw(raw)
263    }
264}
265
266#[derive(Debug, Clone, Hash, PartialEq, Eq)]
267pub struct StackVariableReference {
268    source_operand: u32,
269    pub variable_type: Conf<Ref<Type>>,
270    pub name: String,
271    pub variable: Variable,
272    pub offset: i64,
273    pub size: usize,
274}
275
276impl StackVariableReference {
277    pub(crate) fn from_raw(value: &BNStackVariableReference) -> Self {
278        Self {
279            source_operand: value.sourceOperand,
280            variable_type: Conf::new(
281                unsafe { Type::from_raw(value.type_) }.to_owned(),
282                value.typeConfidence,
283            ),
284            // TODO: I dislike using this function here.
285            name: raw_to_string(value.name).unwrap(),
286            // TODO: It might be beneficial to newtype the identifier as VariableIdentifier.
287            variable: Variable::from_identifier(value.varIdentifier),
288            offset: value.referencedOffset,
289            size: value.size,
290        }
291    }
292
293    pub(crate) fn from_owned_raw(value: BNStackVariableReference) -> Self {
294        let owned = Self::from_raw(&value);
295        Self::free_raw(value);
296        owned
297    }
298
299    pub(crate) fn into_raw(value: Self) -> BNStackVariableReference {
300        let bn_name = BnString::new(value.name);
301        BNStackVariableReference {
302            sourceOperand: value.source_operand,
303            typeConfidence: value.variable_type.confidence,
304            type_: unsafe { Ref::into_raw(value.variable_type.contents) }.handle,
305            name: BnString::into_raw(bn_name),
306            varIdentifier: value.variable.to_identifier(),
307            referencedOffset: value.offset,
308            size: value.size,
309        }
310    }
311
312    pub(crate) fn free_raw(value: BNStackVariableReference) {
313        let _ = unsafe { Type::ref_from_raw(value.type_) };
314        unsafe { BnString::free_raw(value.name) };
315    }
316}
317
318impl CoreArrayProvider for StackVariableReference {
319    type Raw = BNStackVariableReference;
320    type Context = ();
321    type Wrapped<'a> = Self;
322}
323
324unsafe impl CoreArrayProviderInner for StackVariableReference {
325    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
326        BNFreeStackVariableReferenceList(raw, count)
327    }
328
329    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
330        StackVariableReference::from_raw(raw)
331    }
332}
333
334#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
335pub struct SSAVariable {
336    pub variable: Variable,
337    pub version: usize,
338}
339
340impl SSAVariable {
341    pub fn new(variable: Variable, version: usize) -> Self {
342        Self { variable, version }
343    }
344}
345
346impl CoreArrayProvider for SSAVariable {
347    type Raw = usize;
348    type Context = Variable;
349    type Wrapped<'a> = Self;
350}
351
352unsafe impl CoreArrayProviderInner for SSAVariable {
353    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
354        BNFreeILInstructionList(raw)
355    }
356
357    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
358        SSAVariable::new(*context, *raw)
359    }
360}
361
362/// Variables exist within functions at Medium Level IL or higher.
363///
364/// As such, they are to be used within the context of a [`Function`].
365/// See [`Function::variable_name`] as an example of how to interact with variables.
366#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
367pub struct Variable {
368    pub ty: VariableSourceType,
369    // TODO: VariableIndex type?
370    pub index: u32,
371    // TODO: Type this to `VariableStorage`
372    pub storage: i64,
373}
374
375impl Variable {
376    pub fn new(ty: VariableSourceType, index: u32, storage: i64) -> Self {
377        Self { ty, index, storage }
378    }
379
380    // TODO: Retype this...
381    // TODO: Add VariableIdentifier
382    // TODO: StackVariableReference has a varIdentifier, i think thats really it.
383    pub fn from_identifier(ident: u64) -> Self {
384        unsafe { BNFromVariableIdentifier(ident) }.into()
385    }
386
387    pub fn to_identifier(&self) -> u64 {
388        let raw = BNVariable::from(*self);
389        unsafe { BNToVariableIdentifier(&raw) }
390    }
391
392    pub fn to_register(&self, arch: CoreArchitecture) -> Option<CoreRegister> {
393        match self.ty {
394            VariableSourceType::RegisterVariableSourceType => {
395                arch.register_from_id(RegisterId(self.storage as u32))
396            }
397            VariableSourceType::StackVariableSourceType => None,
398            VariableSourceType::FlagVariableSourceType => None,
399        }
400    }
401}
402
403impl From<BNVariable> for Variable {
404    fn from(value: BNVariable) -> Self {
405        Self {
406            ty: value.type_,
407            index: value.index,
408            storage: value.storage,
409        }
410    }
411}
412
413impl From<&BNVariable> for Variable {
414    fn from(value: &BNVariable) -> Self {
415        Self::from(*value)
416    }
417}
418
419impl From<Variable> for BNVariable {
420    fn from(value: Variable) -> Self {
421        Self {
422            type_: value.ty,
423            index: value.index,
424            storage: value.storage,
425        }
426    }
427}
428
429impl From<&Variable> for BNVariable {
430    fn from(value: &Variable) -> Self {
431        BNVariable::from(*value)
432    }
433}
434
435impl CoreArrayProvider for Variable {
436    type Raw = BNVariable;
437    type Context = ();
438    type Wrapped<'a> = Self;
439}
440
441unsafe impl CoreArrayProviderInner for Variable {
442    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
443        BNFreeVariableList(raw)
444    }
445
446    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
447        Variable::from(raw)
448    }
449}
450
451#[derive(Debug, Clone, Hash, PartialEq, Eq)]
452pub struct MergedVariable {
453    pub target: Variable,
454    pub sources: Vec<Variable>,
455}
456
457impl MergedVariable {
458    pub(crate) fn from_raw(value: &BNMergedVariable) -> Self {
459        let raw_sources = unsafe { std::slice::from_raw_parts(value.sources, value.sourceCount) };
460        Self {
461            target: value.target.into(),
462            sources: raw_sources.iter().map(Into::into).collect(),
463        }
464    }
465
466    // TODO: If we want from_owned_raw/free_raw/into_raw we need a way to allocate sources.
467}
468
469impl CoreArrayProvider for MergedVariable {
470    type Raw = BNMergedVariable;
471    type Context = ();
472    type Wrapped<'a> = Self;
473}
474
475unsafe impl CoreArrayProviderInner for MergedVariable {
476    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
477        BNFreeMergedVariableList(raw, count)
478    }
479
480    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
481        Self::from_raw(raw)
482    }
483}
484
485// TODO: This is used in MLIL and HLIL, this really should exist in each of those.
486#[derive(Clone, Debug, Hash, Eq, PartialEq)]
487pub struct ConstantData {
488    // TODO: We really do not want to store a ref to function here.
489    pub function: Ref<Function>,
490    pub value: RegisterValue,
491}
492
493impl ConstantData {
494    pub fn new(function: Ref<Function>, value: RegisterValue) -> Self {
495        Self { function, value }
496    }
497}
498
499#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
500pub struct RegisterValue {
501    pub state: RegisterValueType,
502    // TODO: This value can be anything. Make `T`
503    pub value: i64,
504    pub offset: i64,
505    pub size: usize,
506}
507
508impl RegisterValue {
509    pub fn new(state: RegisterValueType, value: i64, offset: i64, size: usize) -> Self {
510        Self {
511            state,
512            value,
513            offset,
514            size,
515        }
516    }
517}
518
519impl From<BNRegisterValue> for RegisterValue {
520    fn from(value: BNRegisterValue) -> Self {
521        Self {
522            state: value.state,
523            value: value.value,
524            offset: value.offset,
525            size: value.size,
526        }
527    }
528}
529
530impl From<RegisterValue> for BNRegisterValue {
531    fn from(value: RegisterValue) -> Self {
532        Self {
533            state: value.state,
534            value: value.value,
535            offset: value.offset,
536            size: value.size,
537        }
538    }
539}
540
541#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
542pub struct ValueRange<T> {
543    pub start: T,
544    pub end: T,
545    pub step: u64,
546}
547
548impl From<BNValueRange> for ValueRange<u64> {
549    fn from(value: BNValueRange) -> Self {
550        Self {
551            start: value.start,
552            end: value.end,
553            step: value.step,
554        }
555    }
556}
557
558impl From<ValueRange<u64>> for BNValueRange {
559    fn from(value: ValueRange<u64>) -> Self {
560        Self {
561            start: value.start,
562            end: value.end,
563            step: value.step,
564        }
565    }
566}
567
568impl From<BNValueRange> for ValueRange<i64> {
569    fn from(value: BNValueRange) -> Self {
570        Self {
571            start: value.start as i64,
572            end: value.end as i64,
573            step: value.step,
574        }
575    }
576}
577
578impl From<ValueRange<i64>> for BNValueRange {
579    fn from(value: ValueRange<i64>) -> Self {
580        Self {
581            start: value.start as u64,
582            end: value.end as u64,
583            step: value.step,
584        }
585    }
586}
587
588// TODO: Document where its used and why it exists.
589// TODO: What if we are looking up u64?
590#[derive(Clone, Debug, Eq, PartialEq)]
591pub struct LookupTableEntry {
592    /// The set of integers that correspond with [`Self::to`].
593    pub from: HashSet<i64>,
594    /// The associated "mapped" value.
595    pub to: i64,
596}
597
598impl LookupTableEntry {
599    pub(crate) fn from_raw(value: &BNLookupTableEntry) -> Self {
600        let from_values = unsafe { std::slice::from_raw_parts(value.fromValues, value.fromCount) };
601        Self {
602            // TODO: Better way to construct HashSet<i64>?
603            from: HashSet::from_iter(from_values.iter().copied()),
604            to: value.toValue,
605        }
606    }
607
608    pub(crate) fn from_owned_raw(value: BNLookupTableEntry) -> Self {
609        let owned = Self::from_raw(&value);
610        Self::free_raw(value);
611        owned
612    }
613
614    pub(crate) fn into_raw(value: Self) -> BNLookupTableEntry {
615        let from_values: Box<[i64]> = value.from.into_iter().collect();
616        let from_values_len = from_values.len();
617        BNLookupTableEntry {
618            // Freed in [`Self::free_raw`]
619            fromValues: Box::leak(from_values).as_mut_ptr(),
620            fromCount: from_values_len,
621            toValue: value.to,
622        }
623    }
624
625    pub(crate) fn free_raw(value: BNLookupTableEntry) {
626        let raw_from = unsafe { std::slice::from_raw_parts_mut(value.fromValues, value.fromCount) };
627        let boxed_from = unsafe { Box::from_raw(raw_from) };
628    }
629}
630
631#[derive(Debug, Clone, PartialEq, Eq)]
632pub enum PossibleValueSet {
633    UndeterminedValue,
634    EntryValue {
635        // TODO: This is actually the BNVariable storage.
636        // TODO: Type this to `VariableStorage` or something.
637        reg: i64,
638    },
639    ConstantValue {
640        // TODO: Make this T
641        // TODO: This can be really anything (signed, unsigned or even a float).
642        value: i64,
643    },
644    ConstantPointerValue {
645        // TODO: Shouldn't this be u64?
646        value: i64,
647    },
648    ExternalPointerValue {
649        // TODO: Shouldn't this be u64?
650        value: i64,
651        offset: i64,
652    },
653    StackFrameOffset {
654        value: i64,
655    },
656    ReturnAddressValue,
657    ImportedAddressValue {
658        value: i64,
659    },
660    SignedRangeValue {
661        value: i64,
662        ranges: Vec<ValueRange<i64>>,
663    },
664    UnsignedRangeValue {
665        value: i64,
666        ranges: Vec<ValueRange<u64>>,
667    },
668    LookupTableValue {
669        table: Vec<LookupTableEntry>,
670    },
671    InSetOfValues {
672        values: HashSet<i64>,
673    },
674    NotInSetOfValues {
675        values: HashSet<i64>,
676    },
677    // TODO: Can you even get _just_ a constant data value?
678    ConstantDataValue {
679        value: i64,
680        size: usize,
681    },
682    ConstantDataZeroExtendValue {
683        // TODO: Zero extend should be u64?
684        value: i64,
685        size: usize,
686    },
687    ConstantDataSignExtendValue {
688        value: i64,
689        size: usize,
690    },
691    ConstantDataAggregateValue {
692        // WTF is aggregate??
693        value: i64,
694        size: usize,
695    },
696}
697
698impl PossibleValueSet {
699    pub(crate) fn from_raw(value: &BNPossibleValueSet) -> Self {
700        match value.state {
701            RegisterValueType::UndeterminedValue => Self::UndeterminedValue,
702            RegisterValueType::EntryValue => Self::EntryValue { reg: value.value },
703            RegisterValueType::ConstantValue => Self::ConstantValue { value: value.value },
704            RegisterValueType::ConstantPointerValue => {
705                Self::ConstantPointerValue { value: value.value }
706            }
707            RegisterValueType::ExternalPointerValue => Self::ExternalPointerValue {
708                value: value.value,
709                offset: value.offset,
710            },
711            RegisterValueType::StackFrameOffset => Self::StackFrameOffset { value: value.value },
712            RegisterValueType::ReturnAddressValue => Self::ReturnAddressValue,
713            RegisterValueType::ImportedAddressValue => {
714                Self::ImportedAddressValue { value: value.value }
715            }
716            RegisterValueType::SignedRangeValue => {
717                let raw_ranges = unsafe { std::slice::from_raw_parts(value.ranges, value.count) };
718                Self::SignedRangeValue {
719                    value: value.value,
720                    ranges: raw_ranges.iter().map(|&r| r.into()).collect(),
721                }
722            }
723            RegisterValueType::UnsignedRangeValue => {
724                let raw_ranges = unsafe { std::slice::from_raw_parts(value.ranges, value.count) };
725                Self::UnsignedRangeValue {
726                    value: value.value,
727                    ranges: raw_ranges.iter().map(|&r| r.into()).collect(),
728                }
729            }
730            RegisterValueType::LookupTableValue => {
731                let raw_entries = unsafe { std::slice::from_raw_parts(value.table, value.count) };
732                Self::LookupTableValue {
733                    table: raw_entries.iter().map(LookupTableEntry::from_raw).collect(),
734                }
735            }
736            RegisterValueType::InSetOfValues => {
737                let raw_values = unsafe { std::slice::from_raw_parts(value.valueSet, value.count) };
738                Self::InSetOfValues {
739                    values: raw_values.iter().copied().collect(),
740                }
741            }
742            RegisterValueType::NotInSetOfValues => {
743                let raw_values = unsafe { std::slice::from_raw_parts(value.valueSet, value.count) };
744                Self::NotInSetOfValues {
745                    values: raw_values.iter().copied().collect(),
746                }
747            }
748            RegisterValueType::ConstantDataValue => Self::ConstantDataValue {
749                value: value.value,
750                size: value.size,
751            },
752            RegisterValueType::ConstantDataZeroExtendValue => Self::ConstantDataZeroExtendValue {
753                value: value.value,
754                size: value.size,
755            },
756            RegisterValueType::ConstantDataSignExtendValue => Self::ConstantDataSignExtendValue {
757                value: value.value,
758                size: value.size,
759            },
760            RegisterValueType::ConstantDataAggregateValue => Self::ConstantDataAggregateValue {
761                value: value.value,
762                size: value.size,
763            },
764        }
765    }
766
767    /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
768    pub(crate) fn from_owned_core_raw(mut value: BNPossibleValueSet) -> Self {
769        let owned = Self::from_raw(&value);
770        Self::free_core_raw(&mut value);
771        owned
772    }
773
774    pub(crate) fn into_rust_raw(value: Self) -> BNPossibleValueSet {
775        let mut raw = BNPossibleValueSet {
776            state: value.value_type(),
777            ..Default::default()
778        };
779        match value {
780            PossibleValueSet::UndeterminedValue => {}
781            PossibleValueSet::EntryValue { reg } => {
782                raw.value = reg;
783            }
784            PossibleValueSet::ConstantValue { value } => {
785                raw.value = value;
786            }
787            PossibleValueSet::ConstantPointerValue { value } => {
788                raw.value = value;
789            }
790            PossibleValueSet::ExternalPointerValue { value, offset } => {
791                raw.value = value;
792                raw.offset = offset;
793            }
794            PossibleValueSet::StackFrameOffset { value } => {
795                raw.value = value;
796            }
797            PossibleValueSet::ReturnAddressValue => {}
798            PossibleValueSet::ImportedAddressValue { value } => {
799                raw.value = value;
800            }
801            PossibleValueSet::SignedRangeValue { value, ranges } => {
802                let boxed_raw_ranges: Box<[BNValueRange]> =
803                    ranges.into_iter().map(BNValueRange::from).collect();
804                raw.value = value;
805                raw.count = boxed_raw_ranges.len();
806                // NOTE: We are allocating this in rust, meaning core MUST NOT free this.
807                raw.ranges = Box::leak(boxed_raw_ranges).as_mut_ptr();
808            }
809            PossibleValueSet::UnsignedRangeValue { value, ranges } => {
810                let boxed_raw_ranges: Box<[BNValueRange]> =
811                    ranges.into_iter().map(BNValueRange::from).collect();
812                raw.value = value;
813                raw.count = boxed_raw_ranges.len();
814                // NOTE: We are allocating this in rust, meaning core MUST NOT free this.
815                raw.ranges = Box::leak(boxed_raw_ranges).as_mut_ptr();
816            }
817            PossibleValueSet::LookupTableValue { table } => {
818                let boxed_raw_entries: Box<[BNLookupTableEntry]> =
819                    table.into_iter().map(LookupTableEntry::into_raw).collect();
820                raw.count = boxed_raw_entries.len();
821                // NOTE: We are allocating this in rust, meaning core MUST NOT free this.
822                raw.table = Box::leak(boxed_raw_entries).as_mut_ptr();
823            }
824            PossibleValueSet::InSetOfValues { values } => {
825                let boxed_raw_values: Box<[i64]> = values.into_iter().collect();
826                raw.count = boxed_raw_values.len();
827                // NOTE: We are allocating this in rust, meaning core MUST NOT free this.
828                raw.valueSet = Box::leak(boxed_raw_values).as_mut_ptr();
829            }
830            PossibleValueSet::NotInSetOfValues { values } => {
831                let boxed_raw_values: Box<[i64]> = values.into_iter().collect();
832                raw.count = boxed_raw_values.len();
833                // NOTE: We are allocating this in rust, meaning core MUST NOT free this.
834                raw.valueSet = Box::leak(boxed_raw_values).as_mut_ptr();
835            }
836            PossibleValueSet::ConstantDataValue { value, size } => {
837                raw.value = value;
838                raw.size = size;
839            }
840            PossibleValueSet::ConstantDataZeroExtendValue { value, size } => {
841                raw.value = value;
842                raw.size = size;
843            }
844            PossibleValueSet::ConstantDataSignExtendValue { value, size } => {
845                raw.value = value;
846                raw.size = size;
847            }
848            PossibleValueSet::ConstantDataAggregateValue { value, size } => {
849                raw.value = value;
850                raw.size = size;
851            }
852        };
853        raw
854    }
855
856    /// Free a CORE ALLOCATED possible value set. Do not use this with [Self::into_rust_raw] values.
857    pub(crate) fn free_core_raw(value: &mut BNPossibleValueSet) {
858        unsafe { BNFreePossibleValueSet(value) }
859    }
860
861    /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
862    pub(crate) fn free_rust_raw(value: BNPossibleValueSet) {
863        // Free the range list
864        if !value.ranges.is_null() {
865            let raw_ranges = unsafe { std::slice::from_raw_parts_mut(value.ranges, value.count) };
866            let boxed_ranges = unsafe { Box::from_raw(raw_ranges) };
867        }
868
869        if !value.table.is_null() {
870            unsafe { LookupTableEntry::free_raw(*value.table) };
871        }
872
873        if !value.valueSet.is_null() {
874            let raw_value_set =
875                unsafe { std::slice::from_raw_parts_mut(value.valueSet, value.count) };
876            let boxed_value_set = unsafe { Box::from_raw(raw_value_set) };
877        }
878    }
879
880    pub fn value_type(&self) -> RegisterValueType {
881        match self {
882            PossibleValueSet::UndeterminedValue => RegisterValueType::UndeterminedValue,
883            PossibleValueSet::EntryValue { .. } => RegisterValueType::EntryValue,
884            PossibleValueSet::ConstantValue { .. } => RegisterValueType::ConstantValue,
885            PossibleValueSet::ConstantPointerValue { .. } => {
886                RegisterValueType::ConstantPointerValue
887            }
888            PossibleValueSet::ExternalPointerValue { .. } => {
889                RegisterValueType::ExternalPointerValue
890            }
891            PossibleValueSet::StackFrameOffset { .. } => RegisterValueType::StackFrameOffset,
892            PossibleValueSet::ReturnAddressValue => RegisterValueType::ReturnAddressValue,
893            PossibleValueSet::ImportedAddressValue { .. } => {
894                RegisterValueType::ImportedAddressValue
895            }
896            PossibleValueSet::SignedRangeValue { .. } => RegisterValueType::SignedRangeValue,
897            PossibleValueSet::UnsignedRangeValue { .. } => RegisterValueType::UnsignedRangeValue,
898            PossibleValueSet::LookupTableValue { .. } => RegisterValueType::LookupTableValue,
899            PossibleValueSet::InSetOfValues { .. } => RegisterValueType::InSetOfValues,
900            PossibleValueSet::NotInSetOfValues { .. } => RegisterValueType::NotInSetOfValues,
901            PossibleValueSet::ConstantDataValue { .. } => RegisterValueType::ConstantDataValue,
902            PossibleValueSet::ConstantDataZeroExtendValue { .. } => {
903                RegisterValueType::ConstantDataZeroExtendValue
904            }
905            PossibleValueSet::ConstantDataSignExtendValue { .. } => {
906                RegisterValueType::ConstantDataSignExtendValue
907            }
908            PossibleValueSet::ConstantDataAggregateValue { .. } => {
909                RegisterValueType::ConstantDataAggregateValue
910            }
911        }
912    }
913}
914
915#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
916pub struct IndirectBranchInfo {
917    pub source: Location,
918    pub dest: Location,
919    pub auto_defined: bool,
920}
921
922impl From<BNIndirectBranchInfo> for IndirectBranchInfo {
923    fn from(value: BNIndirectBranchInfo) -> Self {
924        Self {
925            source: Location::from_raw(value.sourceAddr, value.sourceArch),
926            dest: Location::from_raw(value.destAddr, value.destArch),
927            auto_defined: value.autoDefined,
928        }
929    }
930}
931
932impl From<IndirectBranchInfo> for BNIndirectBranchInfo {
933    fn from(value: IndirectBranchInfo) -> Self {
934        let source_arch = value
935            .source
936            .arch
937            .map(|a| a.handle)
938            .unwrap_or(std::ptr::null_mut());
939        let dest_arch = value
940            .source
941            .arch
942            .map(|a| a.handle)
943            .unwrap_or(std::ptr::null_mut());
944        Self {
945            sourceArch: source_arch,
946            sourceAddr: value.source.addr,
947            destArch: dest_arch,
948            destAddr: value.dest.addr,
949            autoDefined: value.auto_defined,
950        }
951    }
952}
953
954impl CoreArrayProvider for IndirectBranchInfo {
955    type Raw = BNIndirectBranchInfo;
956    type Context = ();
957    type Wrapped<'a> = Self;
958}
959
960unsafe impl CoreArrayProviderInner for IndirectBranchInfo {
961    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
962        BNFreeIndirectBranchList(raw)
963    }
964
965    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
966        Self::from(*raw)
967    }
968}