binaryninja/
types.rs

1// Copyright 2021-2026 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! The model for representing types in Binary Ninja.
15//!
16//! [`Type`]'s are fundamental to analysis. With types, you can influence how decompilation resolves accesses,
17//! renders data, and tell the analysis of properties such as volatility and constness.
18//!
19//! Types are typically stored within a [`BinaryView`], [`TypeArchive`] or a [`TypeLibrary`].
20//!
21//! Types can be created using the [`TypeBuilder`] or one of the convenience functions. Another way
22//! to create a type is with a [`TypeParser`] if you have C type definitions.
23//!
24//! Some interfaces may expect to be passed a [`TypeContainer`] which itself does not store any type
25//! information, rather a generic interface to query for types by name or by id.
26
27pub mod archive;
28pub mod container;
29pub mod enumeration;
30pub mod library;
31pub mod parser;
32pub mod printer;
33pub mod structure;
34
35use binaryninjacore_sys::*;
36
37use crate::{
38    architecture::{Architecture, Register, RegisterId},
39    binary_view::BinaryView,
40    calling_convention::CoreCallingConvention,
41    rc::*,
42    string::{BnString, IntoCStr},
43};
44
45use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
46use crate::string::raw_to_string;
47use crate::variable::{Variable, VariableSourceType};
48use std::num::NonZeroUsize;
49use std::{
50    collections::HashSet,
51    fmt::{Debug, Display, Formatter},
52    hash::{Hash, Hasher},
53    iter::IntoIterator,
54};
55
56pub use archive::{TypeArchive, TypeArchiveId, TypeArchiveSnapshotId};
57pub use container::TypeContainer;
58pub use enumeration::{Enumeration, EnumerationBuilder, EnumerationMember};
59pub use library::TypeLibrary;
60pub use parser::{
61    CoreTypeParser, ParsedType, TypeParser, TypeParserError, TypeParserErrorSeverity,
62    TypeParserResult,
63};
64pub use printer::{CoreTypePrinter, TypePrinter};
65pub use structure::{
66    BaseStructure, InheritedStructureMember, Structure, StructureBuilder, StructureMember,
67};
68
69#[deprecated(note = "Use crate::qualified_name::QualifiedName instead")]
70// Re-export QualifiedName so that we do not break public consumers.
71pub use crate::qualified_name::QualifiedName;
72
73pub type StructureType = BNStructureVariant;
74pub type ReferenceType = BNReferenceType;
75pub type TypeClass = BNTypeClass;
76pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
77pub type MemberAccess = BNMemberAccess;
78pub type MemberScope = BNMemberScope;
79pub type IntegerDisplayType = BNIntegerDisplayType;
80pub type PointerBaseType = BNPointerBaseType;
81
82#[derive(PartialEq, Eq, Hash)]
83pub struct TypeBuilder {
84    pub(crate) handle: *mut BNTypeBuilder,
85}
86
87impl TypeBuilder {
88    pub fn new(t: &Type) -> Self {
89        unsafe { Self::from_raw(BNCreateTypeBuilderFromType(t.handle)) }
90    }
91
92    pub(crate) unsafe fn from_raw(handle: *mut BNTypeBuilder) -> Self {
93        debug_assert!(!handle.is_null());
94        Self { handle }
95    }
96
97    /// Turn the [`TypeBuilder`] into a [`Type`].
98    pub fn finalize(&self) -> Ref<Type> {
99        unsafe { Type::ref_from_raw(BNFinalizeTypeBuilder(self.handle)) }
100    }
101
102    pub fn set_can_return<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
103        let mut bool_with_confidence = value.into().into();
104        unsafe { BNSetFunctionTypeBuilderCanReturn(self.handle, &mut bool_with_confidence) };
105        self
106    }
107
108    pub fn set_pure<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
109        let mut bool_with_confidence = value.into().into();
110        unsafe { BNSetTypeBuilderPure(self.handle, &mut bool_with_confidence) };
111        self
112    }
113
114    pub fn set_const<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
115        let mut bool_with_confidence = value.into().into();
116        unsafe { BNTypeBuilderSetConst(self.handle, &mut bool_with_confidence) };
117        self
118    }
119
120    pub fn set_volatile<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
121        let mut bool_with_confidence = value.into().into();
122        unsafe { BNTypeBuilderSetVolatile(self.handle, &mut bool_with_confidence) };
123        self
124    }
125
126    /// Set the width of the type.
127    ///
128    /// Typically only done for named type references, which will not have their width set otherwise.
129    pub fn set_width(&self, width: usize) -> &Self {
130        unsafe { BNTypeBuilderSetWidth(self.handle, width) }
131        self
132    }
133
134    /// Set the alignment of the type.
135    ///
136    /// Typically only done for named type references, which will not have their alignment set otherwise.
137    pub fn set_alignment(&self, alignment: usize) -> &Self {
138        unsafe { BNTypeBuilderSetAlignment(self.handle, alignment) }
139        self
140    }
141
142    pub fn set_pointer_base(&self, base_type: PointerBaseType, base_offset: i64) -> &Self {
143        unsafe { BNSetTypeBuilderPointerBase(self.handle, base_type, base_offset) }
144        self
145    }
146
147    pub fn set_child_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
148        let mut type_with_confidence = Conf::<&Type>::into_raw(ty.into());
149        unsafe { BNTypeBuilderSetChildType(self.handle, &mut type_with_confidence) };
150        self
151    }
152
153    /// This is an alias for [`Self::set_child_type`].
154    pub fn set_target<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
155        self.set_child_type(ty)
156    }
157
158    /// This is an alias for [`Self::set_child_type`].
159    pub fn set_element_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
160        self.set_child_type(ty)
161    }
162
163    /// This is an alias for [`Self::set_child_type`].
164    pub fn set_return_value<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
165        self.set_child_type(ty)
166    }
167
168    pub fn set_signed<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
169        let mut bool_with_confidence = value.into().into();
170        unsafe { BNTypeBuilderSetSigned(self.handle, &mut bool_with_confidence) };
171        self
172    }
173
174    pub fn set_integer_display_type(&self, display_type: IntegerDisplayType) -> &Self {
175        unsafe { BNSetIntegerTypeDisplayType(self.handle, display_type) };
176        self
177    }
178
179    // Readable properties
180
181    pub fn type_class(&self) -> TypeClass {
182        unsafe { BNGetTypeBuilderClass(self.handle) }
183    }
184
185    pub fn width(&self) -> u64 {
186        unsafe { BNGetTypeBuilderWidth(self.handle) }
187    }
188
189    pub fn alignment(&self) -> usize {
190        unsafe { BNGetTypeBuilderAlignment(self.handle) }
191    }
192
193    pub fn is_signed(&self) -> Conf<bool> {
194        unsafe { BNIsTypeBuilderSigned(self.handle).into() }
195    }
196
197    pub fn integer_display_type(&self) -> IntegerDisplayType {
198        self.finalize().integer_display_type()
199    }
200
201    pub fn is_const(&self) -> Conf<bool> {
202        unsafe { BNIsTypeBuilderConst(self.handle).into() }
203    }
204
205    pub fn is_volatile(&self) -> Conf<bool> {
206        unsafe { BNIsTypeBuilderVolatile(self.handle).into() }
207    }
208
209    pub fn is_floating_point(&self) -> bool {
210        unsafe { BNIsTypeBuilderFloatingPoint(self.handle) }
211    }
212
213    pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
214        let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
215        match raw_target.type_.is_null() {
216            false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
217            true => None,
218        }
219    }
220
221    /// This is an alias for [`Self::child_type`].
222    pub fn target(&self) -> Option<Conf<Ref<Type>>> {
223        self.child_type()
224    }
225
226    /// This is an alias for [`Self::child_type`].
227    pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
228        self.child_type()
229    }
230
231    /// This is an alias for [`Self::child_type`].
232    pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
233        self.child_type()
234    }
235
236    pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
237        let raw_convention_confidence = unsafe { BNGetTypeBuilderCallingConvention(self.handle) };
238        match raw_convention_confidence.convention.is_null() {
239            false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
240                raw_convention_confidence,
241            )),
242            true => None,
243        }
244    }
245
246    pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
247        unsafe {
248            let mut count = 0;
249            let raw_parameters_ptr = BNGetTypeBuilderParameters(self.handle, &mut count);
250            match raw_parameters_ptr.is_null() {
251                false => {
252                    let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
253                    let parameters = raw_parameters
254                        .iter()
255                        .map(FunctionParameter::from_raw)
256                        .collect();
257                    BNFreeTypeParameterList(raw_parameters_ptr, count);
258                    Some(parameters)
259                }
260                true => None,
261            }
262        }
263    }
264
265    pub fn has_variable_arguments(&self) -> Conf<bool> {
266        unsafe { BNTypeBuilderHasVariableArguments(self.handle).into() }
267    }
268
269    pub fn can_return(&self) -> Conf<bool> {
270        unsafe { BNFunctionTypeBuilderCanReturn(self.handle).into() }
271    }
272
273    pub fn pure(&self) -> Conf<bool> {
274        unsafe { BNIsTypeBuilderPure(self.handle).into() }
275    }
276
277    // TODO: This naming is problematic... rename to `as_structure`?
278    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
279    pub fn get_structure(&self) -> Option<Ref<Structure>> {
280        let raw_struct_ptr = unsafe { BNGetTypeBuilderStructure(self.handle) };
281        match raw_struct_ptr.is_null() {
282            false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
283            true => None,
284        }
285    }
286
287    // TODO: This naming is problematic... rename to `as_enumeration`?
288    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
289    pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
290        let raw_enum_ptr = unsafe { BNGetTypeBuilderEnumeration(self.handle) };
291        match raw_enum_ptr.is_null() {
292            false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
293            true => None,
294        }
295    }
296
297    // TODO: This naming is problematic... rename to `as_named_type_reference`?
298    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
299    pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
300        let raw_type_ref_ptr = unsafe { BNGetTypeBuilderNamedTypeReference(self.handle) };
301        match raw_type_ref_ptr.is_null() {
302            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
303            true => None,
304        }
305    }
306
307    pub fn count(&self) -> u64 {
308        unsafe { BNGetTypeBuilderElementCount(self.handle) }
309    }
310
311    pub fn offset(&self) -> u64 {
312        unsafe { BNGetTypeBuilderOffset(self.handle) }
313    }
314
315    pub fn stack_adjustment(&self) -> Conf<i64> {
316        unsafe { BNGetTypeBuilderStackAdjustment(self.handle).into() }
317    }
318
319    pub fn pointer_base_type(&self) -> PointerBaseType {
320        unsafe { BNTypeBuilderGetPointerBaseType(self.handle) }
321    }
322
323    pub fn pointer_base_offset(&self) -> i64 {
324        unsafe { BNTypeBuilderGetPointerBaseOffset(self.handle) }
325    }
326
327    // TODO : This and properties
328    // pub fn tokens(&self) -> ? {}
329
330    /// Create a void [`TypeBuilder`]. Analogous to [`Type::void`].
331    pub fn void() -> Self {
332        unsafe { Self::from_raw(BNCreateVoidTypeBuilder()) }
333    }
334
335    /// Create a bool [`TypeBuilder`]. Analogous to [`Type::bool`].
336    pub fn bool() -> Self {
337        unsafe { Self::from_raw(BNCreateBoolTypeBuilder()) }
338    }
339
340    /// Create a signed one byte integer [`TypeBuilder`]. Analogous to [`Type::char`].
341    pub fn char() -> Self {
342        Self::int(1, true)
343    }
344
345    /// Create an integer [`TypeBuilder`] with the given width and signedness. Analogous to [`Type::int`].
346    pub fn int(width: usize, is_signed: bool) -> Self {
347        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
348
349        unsafe {
350            Self::from_raw(BNCreateIntegerTypeBuilder(
351                width,
352                &mut is_signed,
353                c"".as_ptr() as _,
354            ))
355        }
356    }
357
358    /// Create an integer [`TypeBuilder`] with the given width and signedness and an alternative name.
359    /// Analogous to [`Type::named_int`].
360    pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Self {
361        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
362        let alt_name = alt_name.to_cstr();
363
364        unsafe {
365            Self::from_raw(BNCreateIntegerTypeBuilder(
366                width,
367                &mut is_signed,
368                alt_name.as_ref().as_ptr() as _,
369            ))
370        }
371    }
372
373    /// Create a float [`TypeBuilder`] with the given width. Analogous to [`Type::float`].
374    pub fn float(width: usize) -> Self {
375        unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, c"".as_ptr())) }
376    }
377
378    /// Create a float [`TypeBuilder`] with the given width and alternative name. Analogous to [`Type::named_float`].
379    pub fn named_float(width: usize, alt_name: &str) -> Self {
380        let alt_name = alt_name.to_cstr();
381        unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, alt_name.as_ptr())) }
382    }
383
384    /// Create an array [`TypeBuilder`] with the given element type and count. Analogous to [`Type::array`].
385    pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Self {
386        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
387        unsafe { Self::from_raw(BNCreateArrayTypeBuilder(&owned_raw_ty, count)) }
388    }
389
390    /// Create an enumeration [`TypeBuilder`] with the given width and signedness. Analogous to [`Type::enumeration`].
391    ///
392    /// ## NOTE
393    ///
394    /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0.
395    ///
396    /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
397    pub fn enumeration<T: Into<Conf<bool>>>(
398        enumeration: &Enumeration,
399        width: NonZeroUsize,
400        is_signed: T,
401    ) -> Self {
402        unsafe {
403            Self::from_raw(BNCreateEnumerationTypeBuilder(
404                // TODO: We pass nullptr arch, really we should not even be passing arch.
405                std::ptr::null_mut(),
406                enumeration.handle,
407                width.get(),
408                &mut is_signed.into().into(),
409            ))
410        }
411    }
412
413    /// Create a structure [`TypeBuilder`]. Analogous to [`Type::structure`].
414    pub fn structure(structure_type: &Structure) -> Self {
415        unsafe { Self::from_raw(BNCreateStructureTypeBuilder(structure_type.handle)) }
416    }
417
418    /// Create a named type reference [`TypeBuilder`]. Analogous to [`Type::named_type`].
419    pub fn named_type(type_reference: &NamedTypeReference) -> Self {
420        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
421        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
422        unsafe {
423            Self::from_raw(BNCreateNamedTypeReferenceBuilder(
424                type_reference.handle,
425                0,
426                1,
427                &mut is_const,
428                &mut is_volatile,
429            ))
430        }
431    }
432
433    /// Create a named type reference [`TypeBuilder`] from a type and name. Analogous to [`Type::named_type_from_type`].
434    pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Self {
435        let mut raw_name = QualifiedName::into_raw(name.into());
436        let id = c"";
437
438        let result = unsafe {
439            Self::from_raw(BNCreateNamedTypeReferenceBuilderFromTypeAndId(
440                id.as_ptr() as *mut _,
441                &mut raw_name,
442                t.handle,
443            ))
444        };
445        QualifiedName::free_raw(raw_name);
446        result
447    }
448
449    // TODO: Deprecate this for a FunctionBuilder (along with the Type variant?)
450    /// NOTE: This is likely to be deprecated and removed in favor of a function type builder, please
451    /// use [`Type::function`] where possible.
452    pub fn function<T: Into<ReturnValue>>(
453        return_value: T,
454        parameters: Vec<FunctionParameter>,
455        variable_arguments: bool,
456    ) -> Self {
457        let mut owned_raw_return_value = ReturnValue::into_rust_raw(&return_value.into());
458        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
459        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
460        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
461
462        let mut raw_calling_convention: BNCallingConventionWithConfidence =
463            BNCallingConventionWithConfidence {
464                convention: std::ptr::null_mut(),
465                confidence: MIN_CONFIDENCE,
466            };
467
468        let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
469        let mut raw_parameters = parameters
470            .into_iter()
471            .map(FunctionParameter::into_raw)
472            .collect::<Vec<_>>();
473        let reg_stack_adjust_regs = std::ptr::null_mut();
474        let reg_stack_adjust_values = std::ptr::null_mut();
475
476        let result = unsafe {
477            Self::from_raw(BNCreateFunctionTypeBuilder(
478                &mut owned_raw_return_value,
479                &mut raw_calling_convention,
480                raw_parameters.as_mut_ptr(),
481                raw_parameters.len(),
482                &mut variable_arguments,
483                &mut can_return,
484                &mut stack_adjust,
485                reg_stack_adjust_regs,
486                reg_stack_adjust_values,
487                0,
488                BNNameType::NoNameType,
489                &mut pure,
490            ))
491        };
492
493        for raw_param in raw_parameters {
494            FunctionParameter::free_raw(raw_param);
495        }
496
497        result
498    }
499
500    // TODO: Deprecate this for a FunctionBuilder (along with the Type variant?)
501    /// NOTE: This is likely to be deprecated and removed in favor of a function type builder, please
502    /// use [`Type::function_with_opts`] where possible.
503    pub fn function_with_opts<T: Into<ReturnValue>, C: Into<Conf<Ref<CoreCallingConvention>>>>(
504        return_value: T,
505        parameters: &[FunctionParameter],
506        variable_arguments: bool,
507        calling_convention: C,
508        stack_adjust: Conf<i64>,
509    ) -> Self {
510        let mut owned_raw_return_value = ReturnValue::into_rust_raw(&return_value.into());
511        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
512        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
513        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
514
515        let mut owned_raw_calling_convention =
516            Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
517
518        let mut stack_adjust = stack_adjust.into();
519        let mut raw_parameters = parameters
520            .iter()
521            .cloned()
522            .map(FunctionParameter::into_raw)
523            .collect::<Vec<_>>();
524
525        // TODO: Update type signature and include these (will be a breaking change)
526        let reg_stack_adjust_regs = std::ptr::null_mut();
527        let reg_stack_adjust_values = std::ptr::null_mut();
528
529        let result = unsafe {
530            Self::from_raw(BNCreateFunctionTypeBuilder(
531                &mut owned_raw_return_value,
532                &mut owned_raw_calling_convention,
533                raw_parameters.as_mut_ptr(),
534                raw_parameters.len(),
535                &mut variable_arguments,
536                &mut can_return,
537                &mut stack_adjust,
538                reg_stack_adjust_regs,
539                reg_stack_adjust_values,
540                0,
541                BNNameType::NoNameType,
542                &mut pure,
543            ))
544        };
545
546        for raw_param in raw_parameters {
547            FunctionParameter::free_raw(raw_param);
548        }
549
550        result
551    }
552
553    /// Create a pointer [`TypeBuilder`] with the given target type. Analogous to [`Type::pointer`].
554    pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
555        Self::pointer_with_options(arch, ty, false, false, None)
556    }
557
558    /// Create a const pointer [`TypeBuilder`] with the given target type. Analogous to [`Type::const_pointer`].
559    pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
560        Self::pointer_with_options(arch, ty, true, false, None)
561    }
562
563    pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
564        arch: &A,
565        ty: T,
566        is_const: bool,
567        is_volatile: bool,
568        ref_type: Option<ReferenceType>,
569    ) -> Self {
570        let arch_ptr_size = arch.address_size();
571        Self::pointer_of_width(ty, arch_ptr_size, is_const, is_volatile, ref_type)
572    }
573
574    pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
575        ty: T,
576        size: usize,
577        is_const: bool,
578        is_volatile: bool,
579        ref_type: Option<ReferenceType>,
580    ) -> Self {
581        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
582        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
583        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
584        unsafe {
585            Self::from_raw(BNCreatePointerTypeBuilderOfWidth(
586                size,
587                &owned_raw_ty,
588                &mut is_const,
589                &mut is_volatile,
590                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
591            ))
592        }
593    }
594}
595
596impl Display for TypeBuilder {
597    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
598        write!(f, "{}", unsafe {
599            BnString::into_string(BNGetTypeBuilderString(self.handle, std::ptr::null_mut()))
600        })
601    }
602}
603
604impl Drop for TypeBuilder {
605    fn drop(&mut self) {
606        unsafe { BNFreeTypeBuilder(self.handle) };
607    }
608}
609
610/// The core model for types in Binary Ninja.
611///
612/// A [`Type`] is how we model the storage of a [`Variable`] or [`crate::variable::DataVariable`] as
613/// well as propagate information such as the constness of a variable. Types are also used to declare
614/// function signatures, such as the [`FunctionParameter`]'s and return type.
615///
616/// Types are immutable. To change a type, you must create a new one either using [`TypeBuilder`] or
617/// one of the helper functions:
618///
619/// - [`Type::void`]
620/// - [`Type::bool`]
621/// - [`Type::char`]
622/// - [`Type::wide_char`]
623/// - [`Type::int`], [`Type::named_int`]
624/// - [`Type::float`], [`Type::named_float`]
625/// - [`Type::array`]
626/// - [`Type::enumeration`]
627/// - [`Type::structure`]
628/// - [`Type::named_type`], [`Type::named_type_from_type`]
629/// - [`Type::function`], [`Type::function_with_opts`]
630/// - [`Type::pointer`], [`Type::const_pointer`], [`Type::pointer_of_width`], [`Type::pointer_with_options`]
631///
632/// # Example
633///
634/// As an example, defining a _named_ type within a [`BinaryView`]:
635///
636/// ```no_run
637/// # use binaryninja::types::Type;
638/// let bv = binaryninja::load("example.bin").unwrap();
639/// let my_custom_type_1 = Type::named_int(5, false, "my_w");
640/// let my_custom_type_2 = Type::int(5, false);
641/// bv.define_user_type("int_1", &my_custom_type_1);
642/// bv.define_user_type("int_2", &my_custom_type_2);
643/// ```
644#[repr(transparent)]
645pub struct Type {
646    pub handle: *mut BNType,
647}
648
649impl Type {
650    pub unsafe fn from_raw(handle: *mut BNType) -> Self {
651        debug_assert!(!handle.is_null());
652        Self { handle }
653    }
654
655    pub unsafe fn ref_from_raw(handle: *mut BNType) -> Ref<Self> {
656        debug_assert!(!handle.is_null());
657        Ref::new(Self { handle })
658    }
659
660    pub fn to_builder(&self) -> TypeBuilder {
661        TypeBuilder::new(self)
662    }
663
664    pub fn type_class(&self) -> TypeClass {
665        unsafe { BNGetTypeClass(self.handle) }
666    }
667
668    // TODO: We need to decide on a public type to represent type width.
669    // TODO: The api uses both `u64` and `usize`, pick one or a new type!
670    /// The size of the type in bytes.
671    pub fn width(&self) -> u64 {
672        unsafe { BNGetTypeWidth(self.handle) }
673    }
674
675    pub fn alignment(&self) -> usize {
676        unsafe { BNGetTypeAlignment(self.handle) }
677    }
678
679    pub fn is_signed(&self) -> Conf<bool> {
680        unsafe { BNIsTypeSigned(self.handle).into() }
681    }
682
683    pub fn integer_display_type(&self) -> IntegerDisplayType {
684        unsafe { BNGetIntegerTypeDisplayType(self.handle) }
685    }
686
687    pub fn is_const(&self) -> Conf<bool> {
688        unsafe { BNIsTypeConst(self.handle).into() }
689    }
690
691    pub fn is_volatile(&self) -> Conf<bool> {
692        unsafe { BNIsTypeVolatile(self.handle).into() }
693    }
694
695    pub fn is_floating_point(&self) -> bool {
696        unsafe { BNIsTypeFloatingPoint(self.handle) }
697    }
698
699    pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
700        let raw_target = unsafe { BNGetChildType(self.handle) };
701        match raw_target.type_.is_null() {
702            false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
703            true => None,
704        }
705    }
706
707    /// This is an alias for [`Self::child_type`].
708    pub fn target(&self) -> Option<Conf<Ref<Type>>> {
709        self.child_type()
710    }
711
712    /// This is an alias for [`Self::child_type`].
713    pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
714        self.child_type()
715    }
716
717    /// This is an alias for [`Self::child_type`].
718    pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
719        self.child_type()
720    }
721
722    pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
723        let convention_confidence = unsafe { BNGetTypeCallingConvention(self.handle) };
724        match convention_confidence.convention.is_null() {
725            false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
726                convention_confidence,
727            )),
728            true => None,
729        }
730    }
731
732    pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
733        unsafe {
734            let mut count = 0;
735            let raw_parameters_ptr = BNGetTypeParameters(self.handle, &mut count);
736            match raw_parameters_ptr.is_null() {
737                false => {
738                    let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
739                    let parameters = raw_parameters
740                        .iter()
741                        .map(FunctionParameter::from_raw)
742                        .collect();
743                    BNFreeTypeParameterList(raw_parameters_ptr, count);
744                    Some(parameters)
745                }
746                true => None,
747            }
748        }
749    }
750
751    pub fn has_variable_arguments(&self) -> Conf<bool> {
752        unsafe { BNTypeHasVariableArguments(self.handle).into() }
753    }
754
755    pub fn can_return(&self) -> Conf<bool> {
756        unsafe { BNFunctionTypeCanReturn(self.handle).into() }
757    }
758
759    pub fn pure(&self) -> Conf<bool> {
760        unsafe { BNIsTypePure(self.handle).into() }
761    }
762
763    // TODO: This naming is problematic... rename to `as_structure`?
764    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
765    pub fn get_structure(&self) -> Option<Ref<Structure>> {
766        let raw_struct_ptr = unsafe { BNGetTypeStructure(self.handle) };
767        match raw_struct_ptr.is_null() {
768            false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
769            true => None,
770        }
771    }
772
773    // TODO: This naming is problematic... rename to `as_enumeration`?
774    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
775    pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
776        let raw_enum_ptr = unsafe { BNGetTypeEnumeration(self.handle) };
777        match raw_enum_ptr.is_null() {
778            false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
779            true => None,
780        }
781    }
782
783    // TODO: This naming is problematic... rename to `as_named_type_reference`?
784    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
785    pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
786        let raw_type_ref_ptr = unsafe { BNGetTypeNamedTypeReference(self.handle) };
787        match raw_type_ref_ptr.is_null() {
788            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
789            true => None,
790        }
791    }
792
793    pub fn count(&self) -> u64 {
794        unsafe { BNGetTypeElementCount(self.handle) }
795    }
796
797    pub fn offset(&self) -> u64 {
798        unsafe { BNGetTypeOffset(self.handle) }
799    }
800
801    pub fn stack_adjustment(&self) -> Conf<i64> {
802        unsafe { BNGetTypeStackAdjustment(self.handle).into() }
803    }
804
805    pub fn registered_name(&self) -> Option<Ref<NamedTypeReference>> {
806        let raw_type_ref_ptr = unsafe { BNGetRegisteredTypeName(self.handle) };
807        match raw_type_ref_ptr.is_null() {
808            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
809            true => None,
810        }
811    }
812
813    pub fn pointer_base_type(&self) -> BNPointerBaseType {
814        unsafe { BNTypeGetPointerBaseType(self.handle) }
815    }
816
817    pub fn pointer_base_offset(&self) -> i64 {
818        unsafe { BNTypeGetPointerBaseOffset(self.handle) }
819    }
820
821    // TODO : This and properties
822    // pub fn tokens(&self) -> ? {}
823
824    pub fn void() -> Ref<Self> {
825        unsafe { Self::ref_from_raw(BNCreateVoidType()) }
826    }
827
828    pub fn bool() -> Ref<Self> {
829        unsafe { Self::ref_from_raw(BNCreateBoolType()) }
830    }
831
832    pub fn char() -> Ref<Self> {
833        Self::int(1, true)
834    }
835
836    pub fn wide_char(width: usize) -> Ref<Self> {
837        unsafe { Self::ref_from_raw(BNCreateWideCharType(width, c"".as_ptr())) }
838    }
839
840    pub fn int(width: usize, is_signed: bool) -> Ref<Self> {
841        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
842        unsafe { Self::ref_from_raw(BNCreateIntegerType(width, &mut is_signed, c"".as_ptr())) }
843    }
844
845    pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Ref<Self> {
846        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
847        let alt_name = alt_name.to_cstr();
848
849        unsafe {
850            Self::ref_from_raw(BNCreateIntegerType(
851                width,
852                &mut is_signed,
853                alt_name.as_ptr(),
854            ))
855        }
856    }
857
858    pub fn float(width: usize) -> Ref<Self> {
859        unsafe { Self::ref_from_raw(BNCreateFloatType(width, c"".as_ptr())) }
860    }
861
862    pub fn named_float(width: usize, alt_name: &str) -> Ref<Self> {
863        let alt_name = alt_name.to_cstr();
864        unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ptr())) }
865    }
866
867    pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Ref<Self> {
868        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
869        unsafe { Self::ref_from_raw(BNCreateArrayType(&owned_raw_ty, count)) }
870    }
871
872    /// ## NOTE
873    ///
874    /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0.
875    ///
876    /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
877    pub fn enumeration<T: Into<Conf<bool>>>(
878        enumeration: &Enumeration,
879        width: NonZeroUsize,
880        is_signed: T,
881    ) -> Ref<Self> {
882        unsafe {
883            Self::ref_from_raw(BNCreateEnumerationType(
884                // TODO: We pass nullptr arch, really we should not even be passing arch.
885                std::ptr::null_mut(),
886                enumeration.handle,
887                width.get(),
888                &mut is_signed.into().into(),
889            ))
890        }
891    }
892
893    pub fn structure(structure: &Structure) -> Ref<Self> {
894        unsafe { Self::ref_from_raw(BNCreateStructureType(structure.handle)) }
895    }
896
897    pub fn named_type(type_reference: &NamedTypeReference) -> Ref<Self> {
898        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
899        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
900        unsafe {
901            Self::ref_from_raw(BNCreateNamedTypeReference(
902                type_reference.handle,
903                0,
904                1,
905                &mut is_const,
906                &mut is_volatile,
907            ))
908        }
909    }
910
911    pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Ref<Self> {
912        let mut raw_name = QualifiedName::into_raw(name.into());
913        // TODO: No id is present for this call?
914        let id = c"";
915
916        let result = unsafe {
917            Self::ref_from_raw(BNCreateNamedTypeReferenceFromTypeAndId(
918                id.as_ptr(),
919                &mut raw_name,
920                t.handle,
921            ))
922        };
923        QualifiedName::free_raw(raw_name);
924        result
925    }
926
927    // TODO: FunctionBuilder
928    pub fn function<T: Into<ReturnValue>>(
929        return_value: T,
930        parameters: Vec<FunctionParameter>,
931        variable_arguments: bool,
932    ) -> Ref<Self> {
933        let mut owned_raw_return_value = ReturnValue::into_rust_raw(&return_value.into());
934        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
935        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
936        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
937
938        let mut raw_calling_convention: BNCallingConventionWithConfidence =
939            BNCallingConventionWithConfidence {
940                convention: std::ptr::null_mut(),
941                confidence: MIN_CONFIDENCE,
942            };
943
944        let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
945        let mut raw_parameters = parameters
946            .into_iter()
947            .map(FunctionParameter::into_raw)
948            .collect::<Vec<_>>();
949        let reg_stack_adjust_regs = std::ptr::null_mut();
950        let reg_stack_adjust_values = std::ptr::null_mut();
951
952        let result = unsafe {
953            Self::ref_from_raw(BNCreateFunctionType(
954                &mut owned_raw_return_value,
955                &mut raw_calling_convention,
956                raw_parameters.as_mut_ptr(),
957                raw_parameters.len(),
958                &mut variable_arguments,
959                &mut can_return,
960                &mut stack_adjust,
961                reg_stack_adjust_regs,
962                reg_stack_adjust_values,
963                0,
964                BNNameType::NoNameType,
965                &mut pure,
966            ))
967        };
968
969        ReturnValue::free_rust_raw(owned_raw_return_value);
970        for raw_param in raw_parameters {
971            FunctionParameter::free_raw(raw_param);
972        }
973
974        result
975    }
976
977    // TODO: FunctionBuilder
978    pub fn function_with_opts<T: Into<ReturnValue>, C: Into<Conf<Ref<CoreCallingConvention>>>>(
979        return_value: T,
980        parameters: &[FunctionParameter],
981        variable_arguments: bool,
982        calling_convention: C,
983        stack_adjust: Conf<i64>,
984    ) -> Ref<Self> {
985        let mut owned_raw_return_value = ReturnValue::into_rust_raw(&return_value.into());
986        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
987        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
988        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
989
990        let mut owned_raw_calling_convention =
991            Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
992
993        let mut stack_adjust = stack_adjust.into();
994        let mut raw_parameters = parameters
995            .iter()
996            .cloned()
997            .map(FunctionParameter::into_raw)
998            .collect::<Vec<_>>();
999
1000        // TODO: Update type signature and include these (will be a breaking change)
1001        let reg_stack_adjust_regs = std::ptr::null_mut();
1002        let reg_stack_adjust_values = std::ptr::null_mut();
1003
1004        let result = unsafe {
1005            Self::ref_from_raw(BNCreateFunctionType(
1006                &mut owned_raw_return_value,
1007                &mut owned_raw_calling_convention,
1008                raw_parameters.as_mut_ptr(),
1009                raw_parameters.len(),
1010                &mut variable_arguments,
1011                &mut can_return,
1012                &mut stack_adjust,
1013                reg_stack_adjust_regs,
1014                reg_stack_adjust_values,
1015                0,
1016                BNNameType::NoNameType,
1017                &mut pure,
1018            ))
1019        };
1020
1021        ReturnValue::free_rust_raw(owned_raw_return_value);
1022        for raw_param in raw_parameters {
1023            FunctionParameter::free_raw(raw_param);
1024        }
1025
1026        result
1027    }
1028
1029    pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Ref<Self> {
1030        Self::pointer_with_options(arch, ty, false, false, None)
1031    }
1032
1033    pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
1034        arch: &A,
1035        ty: T,
1036    ) -> Ref<Self> {
1037        Self::pointer_with_options(arch, ty, true, false, None)
1038    }
1039
1040    pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
1041        arch: &A,
1042        ty: T,
1043        is_const: bool,
1044        is_volatile: bool,
1045        ref_type: Option<ReferenceType>,
1046    ) -> Ref<Self> {
1047        let arch_pointer_size = arch.address_size();
1048        Self::pointer_of_width(ty, arch_pointer_size, is_const, is_volatile, ref_type)
1049    }
1050
1051    pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
1052        ty: T,
1053        size: usize,
1054        is_const: bool,
1055        is_volatile: bool,
1056        ref_type: Option<ReferenceType>,
1057    ) -> Ref<Self> {
1058        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
1059        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
1060        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1061        unsafe {
1062            Self::ref_from_raw(BNCreatePointerTypeOfWidth(
1063                size,
1064                &owned_raw_ty,
1065                &mut is_const,
1066                &mut is_volatile,
1067                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
1068            ))
1069        }
1070    }
1071
1072    pub fn generate_auto_demangled_type_id<T: Into<QualifiedName>>(name: T) -> String {
1073        let mut raw_name = QualifiedName::into_raw(name.into());
1074        let type_id =
1075            unsafe { BnString::into_string(BNGenerateAutoDemangledTypeId(&mut raw_name)) };
1076        QualifiedName::free_raw(raw_name);
1077        type_id
1078    }
1079
1080    pub fn deref_named_type_reference(&self, view: &BinaryView) -> Ref<Type> {
1081        unsafe { Self::ref_from_raw(BNDerefNamedTypeReference(view.handle, self.handle)) }
1082    }
1083}
1084
1085impl Display for Type {
1086    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1087        write!(f, "{}", unsafe {
1088            BnString::into_string(BNGetTypeString(
1089                self.handle,
1090                std::ptr::null_mut(),
1091                BNTokenEscapingType::NoTokenEscapingType,
1092            ))
1093        })
1094    }
1095}
1096
1097impl Debug for Type {
1098    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1099        // You might be tempted to rip this atrocity out and make this more "sensible". READ BELOW!
1100        // Type is a one-size fits all structure, these are actually its fields! If we wanted to
1101        // omit some fields for different type classes, what you really want to do is implement your
1102        // own formatter. This is supposed to represent the structure entirely, it's not supposed to be pretty!
1103        f.debug_struct("Type")
1104            .field("type_class", &self.type_class())
1105            .field("width", &self.width())
1106            .field("alignment", &self.alignment())
1107            .field("is_signed", &self.is_signed())
1108            .field("is_const", &self.is_const())
1109            .field("is_volatile", &self.is_volatile())
1110            .field("child_type", &self.child_type())
1111            .field("calling_convention", &self.calling_convention())
1112            .field("parameters", &self.parameters())
1113            .field("has_variable_arguments", &self.has_variable_arguments())
1114            .field("can_return", &self.can_return())
1115            .field("pure", &self.pure())
1116            .field("get_structure", &self.get_structure())
1117            .field("get_enumeration", &self.get_enumeration())
1118            .field("get_named_type_reference", &self.get_named_type_reference())
1119            .field("count", &self.count())
1120            .field("offset", &self.offset())
1121            .field("stack_adjustment", &self.stack_adjustment())
1122            .field("registered_name", &self.registered_name())
1123            .finish()
1124    }
1125}
1126
1127impl PartialEq for Type {
1128    fn eq(&self, other: &Self) -> bool {
1129        unsafe { BNTypesEqual(self.handle, other.handle) }
1130    }
1131}
1132
1133impl Eq for Type {}
1134
1135impl Hash for Type {
1136    fn hash<H: Hasher>(&self, state: &mut H) {
1137        self.handle.hash(state);
1138    }
1139}
1140
1141unsafe impl Send for Type {}
1142unsafe impl Sync for Type {}
1143
1144unsafe impl RefCountable for Type {
1145    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1146        Self::ref_from_raw(BNNewTypeReference(handle.handle))
1147    }
1148
1149    unsafe fn dec_ref(handle: &Self) {
1150        BNFreeType(handle.handle);
1151    }
1152}
1153
1154impl ToOwned for Type {
1155    type Owned = Ref<Self>;
1156
1157    fn to_owned(&self) -> Self::Owned {
1158        unsafe { RefCountable::inc_ref(self) }
1159    }
1160}
1161
1162impl CoreArrayProvider for Type {
1163    type Raw = *mut BNType;
1164    type Context = ();
1165    type Wrapped<'a> = &'a Self;
1166}
1167
1168unsafe impl CoreArrayProviderInner for Type {
1169    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1170        BNFreeTypeList(raw, count)
1171    }
1172
1173    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1174        // TODO: This is assuming &'a Type is &*mut BNType
1175        std::mem::transmute(raw)
1176    }
1177}
1178
1179#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1180pub struct ValueLocationComponent {
1181    pub variable: Variable,
1182    pub offset: i64,
1183    pub size: Option<u64>,
1184}
1185
1186impl ValueLocationComponent {
1187    pub(crate) fn from_raw(value: &BNValueLocationComponent) -> Self {
1188        let variable = Variable::from(&value.variable);
1189        let size = if value.sizeValid {
1190            Some(value.size)
1191        } else {
1192            None
1193        };
1194        Self {
1195            variable,
1196            offset: value.offset,
1197            size,
1198        }
1199    }
1200
1201    pub(crate) fn into_raw(value: &Self) -> BNValueLocationComponent {
1202        BNValueLocationComponent {
1203            variable: value.variable.into(),
1204            offset: value.offset,
1205            sizeValid: value.size.is_some(),
1206            size: value.size.unwrap_or(0),
1207        }
1208    }
1209}
1210
1211#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1212pub struct ValueLocation {
1213    pub components: Vec<ValueLocationComponent>,
1214    pub indirect: bool,
1215    pub returned_pointer: Option<Variable>,
1216}
1217
1218impl ValueLocation {
1219    pub fn from_variable(var: Variable) -> Self {
1220        Self {
1221            components: vec![ValueLocationComponent {
1222                variable: var,
1223                offset: 0,
1224                size: None,
1225            }],
1226            indirect: false,
1227            returned_pointer: None,
1228        }
1229    }
1230
1231    pub fn from_register(reg: impl Register) -> Self {
1232        Self::from_variable(Variable::from_register(reg))
1233    }
1234
1235    pub fn from_register_id(reg: RegisterId) -> Self {
1236        Self::from_variable(Variable::from_register_id(reg))
1237    }
1238
1239    pub fn from_stack_offset(offset: i64) -> Self {
1240        Self::from_variable(Variable::from_stack_offset(offset))
1241    }
1242
1243    pub fn is_valid(&self) -> bool {
1244        !self.components.is_empty()
1245    }
1246
1247    pub fn variable_for_return_value(&self) -> Option<Variable> {
1248        let value_raw = Self::into_rust_raw(self);
1249        let mut var_raw = BNVariable::default();
1250        let valid = unsafe { BNGetValueLocationVariableForReturnValue(&value_raw, &mut var_raw) };
1251        Self::free_rust_raw(value_raw);
1252        if valid {
1253            Some(var_raw.into())
1254        } else {
1255            None
1256        }
1257    }
1258
1259    pub fn variable_for_parameter(&self, idx: usize) -> Option<Variable> {
1260        let value_raw = Self::into_rust_raw(self);
1261        let mut var_raw = BNVariable::default();
1262        let valid =
1263            unsafe { BNGetValueLocationVariableForParameter(&value_raw, &mut var_raw, idx) };
1264        Self::free_rust_raw(value_raw);
1265        if valid {
1266            Some(var_raw.into())
1267        } else {
1268            None
1269        }
1270    }
1271
1272    pub(crate) fn from_raw(loc: &BNValueLocation) -> Self {
1273        let components_raw: &[BNValueLocationComponent] =
1274            unsafe { crate::ffi::slice_from_raw_parts(loc.components, loc.count) };
1275        Self {
1276            components: components_raw
1277                .iter()
1278                .map(ValueLocationComponent::from_raw)
1279                .collect(),
1280            indirect: loc.indirect,
1281            returned_pointer: if loc.returnedPointerValid {
1282                Some(Variable::from(&loc.returnedPointer))
1283            } else {
1284                None
1285            },
1286        }
1287    }
1288
1289    pub fn into_rust_raw(value: &Self) -> BNValueLocation {
1290        let components: Box<[BNValueLocationComponent]> = value
1291            .components
1292            .iter()
1293            .map(ValueLocationComponent::into_raw)
1294            .collect();
1295        BNValueLocation {
1296            count: components.len(),
1297            components: Box::leak(components).as_mut_ptr(),
1298            indirect: value.indirect,
1299            returnedPointerValid: value.returned_pointer.is_some(),
1300            returnedPointer: if let Some(ptr) = value.returned_pointer {
1301                ptr.into()
1302            } else {
1303                Variable::new(VariableSourceType::RegisterVariableSourceType, 0, 0).into()
1304            },
1305        }
1306    }
1307
1308    /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
1309    pub fn free_rust_raw(value: BNValueLocation) {
1310        let raw_components =
1311            unsafe { std::slice::from_raw_parts_mut(value.components, value.count) };
1312        let _ = unsafe { Box::from_raw(raw_components) };
1313    }
1314}
1315
1316impl From<Variable> for ValueLocation {
1317    fn from(value: Variable) -> Self {
1318        ValueLocation {
1319            components: vec![ValueLocationComponent {
1320                variable: value,
1321                offset: 0,
1322                size: None,
1323            }],
1324            indirect: false,
1325            returned_pointer: None,
1326        }
1327    }
1328}
1329
1330#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1331pub struct ReturnValue {
1332    pub ty: Conf<Ref<Type>>,
1333    pub location: Option<Conf<ValueLocation>>,
1334}
1335
1336impl ReturnValue {
1337    pub(crate) fn from_raw(value: &BNReturnValue) -> Self {
1338        Self {
1339            ty: Conf::new(
1340                unsafe { Type::from_raw(value.type_).to_owned() },
1341                value.typeConfidence,
1342            ),
1343            location: match value.defaultLocation {
1344                false => Some(Conf::new(
1345                    ValueLocation::from_raw(&value.location),
1346                    value.locationConfidence,
1347                )),
1348                true => None,
1349            },
1350        }
1351    }
1352
1353    /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
1354    pub(crate) fn from_owned_core_raw(mut value: BNReturnValue) -> Self {
1355        let owned = Self::from_raw(&value);
1356        Self::free_core_raw(&mut value);
1357        owned
1358    }
1359
1360    pub(crate) fn into_rust_raw(value: &Self) -> BNReturnValue {
1361        BNReturnValue {
1362            type_: unsafe { Ref::into_raw(value.ty.contents.clone()) }.handle,
1363            typeConfidence: value.ty.confidence,
1364            defaultLocation: value.location.is_none(),
1365            location: ValueLocation::into_rust_raw(
1366                value
1367                    .location
1368                    .as_ref()
1369                    .map(|v| &v.contents)
1370                    .unwrap_or(&ValueLocation {
1371                        components: Vec::new(),
1372                        indirect: false,
1373                        returned_pointer: None,
1374                    }),
1375            ),
1376            locationConfidence: value.location.as_ref().map(|v| v.confidence).unwrap_or(0),
1377        }
1378    }
1379
1380    /// Free a CORE ALLOCATED possible value set. Do not use this with [Self::into_rust_raw] values.
1381    pub(crate) fn free_core_raw(value: &mut BNReturnValue) {
1382        unsafe { BNFreeReturnValue(value) }
1383    }
1384
1385    /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
1386    pub(crate) fn free_rust_raw(value: BNReturnValue) {
1387        let _ = unsafe { Type::ref_from_raw(value.type_) };
1388        ValueLocation::free_rust_raw(value.location);
1389    }
1390}
1391
1392impl From<Ref<Type>> for ReturnValue {
1393    fn from(value: Ref<Type>) -> ReturnValue {
1394        ReturnValue {
1395            ty: value.into(),
1396            location: None,
1397        }
1398    }
1399}
1400
1401impl From<&Ref<Type>> for ReturnValue {
1402    fn from(value: &Ref<Type>) -> ReturnValue {
1403        ReturnValue {
1404            ty: value.clone().into(),
1405            location: None,
1406        }
1407    }
1408}
1409
1410impl From<&Type> for ReturnValue {
1411    fn from(value: &Type) -> ReturnValue {
1412        ReturnValue {
1413            ty: value.to_owned().into(),
1414            location: None,
1415        }
1416    }
1417}
1418
1419impl From<Conf<Ref<Type>>> for ReturnValue {
1420    fn from(value: Conf<Ref<Type>>) -> ReturnValue {
1421        ReturnValue {
1422            ty: value,
1423            location: None,
1424        }
1425    }
1426}
1427
1428impl From<&Conf<Ref<Type>>> for ReturnValue {
1429    fn from(value: &Conf<Ref<Type>>) -> ReturnValue {
1430        ReturnValue {
1431            ty: value.clone(),
1432            location: None,
1433        }
1434    }
1435}
1436
1437#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1438pub enum ValueLocationSource {
1439    Default,
1440    PassByValue,
1441    PassByReference,
1442    Custom(ValueLocation),
1443}
1444
1445impl From<Option<ValueLocation>> for ValueLocationSource {
1446    fn from(loc: Option<ValueLocation>) -> Self {
1447        match loc {
1448            Some(loc) => ValueLocationSource::Custom(loc),
1449            None => ValueLocationSource::Default,
1450        }
1451    }
1452}
1453
1454#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1455pub struct FunctionParameter {
1456    pub ty: Conf<Ref<Type>>,
1457    pub name: String,
1458    pub location: ValueLocationSource,
1459}
1460
1461impl FunctionParameter {
1462    pub(crate) fn from_raw(value: &BNFunctionParameter) -> Self {
1463        // TODO: I copied this from the original `from_raw` function.
1464        // TODO: So this actually needs to be audited later.
1465        let name = if value.name.is_null() {
1466            String::new()
1467        } else {
1468            raw_to_string(value.name as *const _).unwrap()
1469        };
1470
1471        Self {
1472            ty: Conf::new(
1473                unsafe { Type::from_raw(value.type_).to_owned() },
1474                value.typeConfidence,
1475            ),
1476            name,
1477            location: match value.locationSource {
1478                BNValueLocationSource::DefaultLocationSource => ValueLocationSource::Default,
1479                BNValueLocationSource::PassByValueLocationSource => {
1480                    ValueLocationSource::PassByValue
1481                }
1482                BNValueLocationSource::PassByReferenceLocationSource => {
1483                    ValueLocationSource::PassByReference
1484                }
1485                BNValueLocationSource::CustomLocationSource => {
1486                    ValueLocationSource::Custom(ValueLocation::from_raw(&value.location))
1487                }
1488            },
1489        }
1490    }
1491
1492    #[allow(unused)]
1493    pub(crate) fn from_owned_raw(value: BNFunctionParameter) -> Self {
1494        let owned = Self::from_raw(&value);
1495        Self::free_raw(value);
1496        owned
1497    }
1498
1499    pub(crate) fn into_raw(value: Self) -> BNFunctionParameter {
1500        let bn_name = BnString::new(value.name);
1501        BNFunctionParameter {
1502            name: BnString::into_raw(bn_name),
1503            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
1504            typeConfidence: value.ty.confidence,
1505            locationSource: match value.location {
1506                ValueLocationSource::Default => BNValueLocationSource::DefaultLocationSource,
1507                ValueLocationSource::PassByValue => {
1508                    BNValueLocationSource::PassByValueLocationSource
1509                }
1510                ValueLocationSource::PassByReference => {
1511                    BNValueLocationSource::PassByReferenceLocationSource
1512                }
1513                ValueLocationSource::Custom(_) => BNValueLocationSource::CustomLocationSource,
1514            },
1515            location: match &value.location {
1516                ValueLocationSource::Custom(loc) => ValueLocation::into_rust_raw(loc),
1517                _ => ValueLocation::into_rust_raw(&ValueLocation {
1518                    components: Vec::new(),
1519                    indirect: false,
1520                    returned_pointer: None,
1521                }),
1522            },
1523        }
1524    }
1525
1526    pub(crate) fn free_raw(value: BNFunctionParameter) {
1527        unsafe { BnString::free_raw(value.name) };
1528        let _ = unsafe { Type::ref_from_raw(value.type_) };
1529        ValueLocation::free_rust_raw(value.location);
1530    }
1531
1532    pub fn new<T: Into<Conf<Ref<Type>>>>(
1533        ty: T,
1534        name: String,
1535        location: impl Into<ValueLocationSource>,
1536    ) -> Self {
1537        Self {
1538            ty: ty.into(),
1539            name,
1540            location: location.into(),
1541        }
1542    }
1543}
1544
1545#[derive(PartialEq, Eq, Hash)]
1546pub struct NamedTypeReference {
1547    pub(crate) handle: *mut BNNamedTypeReference,
1548}
1549
1550impl NamedTypeReference {
1551    pub(crate) unsafe fn from_raw(handle: *mut BNNamedTypeReference) -> Self {
1552        debug_assert!(!handle.is_null());
1553        Self { handle }
1554    }
1555
1556    pub(crate) unsafe fn ref_from_raw(handle: *mut BNNamedTypeReference) -> Ref<Self> {
1557        debug_assert!(!handle.is_null());
1558        Ref::new(Self { handle })
1559    }
1560
1561    /// Create an NTR to a type that did not come directly from a BinaryView's types list.
1562    /// That is to say, if you're referencing a new type you're GOING to add, use this.
1563    /// You should not assign type ids yourself, that is the responsibility of the BinaryView
1564    /// implementation after your types have been added. Just make sure the names match up and
1565    /// the core will do the id stuff for you.
1566    pub fn new<T: Into<QualifiedName>>(type_class: NamedTypeReferenceClass, name: T) -> Ref<Self> {
1567        let mut raw_name = QualifiedName::into_raw(name.into());
1568        let result = unsafe {
1569            Self::ref_from_raw(BNCreateNamedType(
1570                type_class,
1571                std::ptr::null(),
1572                &mut raw_name,
1573            ))
1574        };
1575        QualifiedName::free_raw(raw_name);
1576        result
1577    }
1578
1579    /// Create an NTR to a type with an existing type id, which generally means it came directly
1580    /// from a BinaryView's types list and its id was looked up using `BinaryView::get_type_id`.
1581    /// You should not assign type ids yourself: if you use this to reference a type you are going
1582    /// to create but have not yet created, you may run into problems when giving your types to
1583    /// a BinaryView.
1584    pub fn new_with_id<T: Into<QualifiedName>>(
1585        type_class: NamedTypeReferenceClass,
1586        type_id: &str,
1587        name: T,
1588    ) -> Ref<Self> {
1589        let type_id = type_id.to_cstr();
1590        let mut raw_name = QualifiedName::into_raw(name.into());
1591        let result = unsafe {
1592            Self::ref_from_raw(BNCreateNamedType(
1593                type_class,
1594                type_id.as_ref().as_ptr() as _,
1595                &mut raw_name,
1596            ))
1597        };
1598        QualifiedName::free_raw(raw_name);
1599        result
1600    }
1601
1602    pub fn name(&self) -> QualifiedName {
1603        let raw_name = unsafe { BNGetTypeReferenceName(self.handle) };
1604        QualifiedName::from_owned_raw(raw_name)
1605    }
1606
1607    pub fn id(&self) -> String {
1608        unsafe { BnString::into_string(BNGetTypeReferenceId(self.handle)) }
1609    }
1610
1611    pub fn class(&self) -> NamedTypeReferenceClass {
1612        unsafe { BNGetTypeReferenceClass(self.handle) }
1613    }
1614
1615    fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet<String>) -> Option<Ref<Type>> {
1616        let ty = bv.type_by_id(&self.id())?;
1617        match ty.type_class() {
1618            TypeClass::NamedTypeReferenceClass => {
1619                // Recurse into the NTR type until we get the target type.
1620                let ntr = ty
1621                    .get_named_type_reference()
1622                    .expect("NTR type class should always have a valid NTR");
1623                match visited.insert(ntr.id()) {
1624                    true => ntr.target_helper(bv, visited),
1625                    // Cyclic reference, return None.
1626                    false => None,
1627                }
1628            }
1629            // Found target type
1630            _ => Some(ty),
1631        }
1632    }
1633
1634    /// Type referenced by this [`NamedTypeReference`].
1635    ///
1636    /// Will return `None` if the reference is cyclic, or the target type does not exist.
1637    pub fn target(&self, bv: &BinaryView) -> Option<Ref<Type>> {
1638        self.target_helper(bv, &mut HashSet::new())
1639    }
1640}
1641
1642impl ToOwned for NamedTypeReference {
1643    type Owned = Ref<Self>;
1644
1645    fn to_owned(&self) -> Self::Owned {
1646        unsafe { RefCountable::inc_ref(self) }
1647    }
1648}
1649
1650unsafe impl RefCountable for NamedTypeReference {
1651    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1652        Self::ref_from_raw(BNNewNamedTypeReference(handle.handle))
1653    }
1654
1655    unsafe fn dec_ref(handle: &Self) {
1656        BNFreeNamedTypeReference(handle.handle)
1657    }
1658}
1659
1660impl Debug for NamedTypeReference {
1661    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1662        write!(f, "{} (id: {})", self.name(), self.id())
1663    }
1664}
1665
1666#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1667pub struct QualifiedNameAndType {
1668    pub name: QualifiedName,
1669    pub ty: Ref<Type>,
1670}
1671
1672impl QualifiedNameAndType {
1673    pub(crate) fn from_raw(value: &BNQualifiedNameAndType) -> Self {
1674        Self {
1675            name: QualifiedName::from_raw(&value.name),
1676            ty: unsafe { Type::from_raw(value.type_).to_owned() },
1677        }
1678    }
1679
1680    pub(crate) fn from_owned_raw(value: BNQualifiedNameAndType) -> Self {
1681        let owned = Self::from_raw(&value);
1682        Self::free_raw(value);
1683        owned
1684    }
1685
1686    pub(crate) fn into_raw(value: Self) -> BNQualifiedNameAndType {
1687        BNQualifiedNameAndType {
1688            name: QualifiedName::into_raw(value.name),
1689            type_: unsafe { Ref::into_raw(value.ty).handle },
1690        }
1691    }
1692
1693    pub(crate) fn free_raw(value: BNQualifiedNameAndType) {
1694        QualifiedName::free_raw(value.name);
1695        let _ = unsafe { Type::ref_from_raw(value.type_) };
1696    }
1697
1698    pub fn new(name: QualifiedName, ty: Ref<Type>) -> Self {
1699        Self { name, ty }
1700    }
1701}
1702
1703impl<T> From<(T, Ref<Type>)> for QualifiedNameAndType
1704where
1705    T: Into<QualifiedName>,
1706{
1707    fn from(value: (T, Ref<Type>)) -> Self {
1708        Self {
1709            name: value.0.into(),
1710            ty: value.1,
1711        }
1712    }
1713}
1714
1715impl<T> From<(T, &Type)> for QualifiedNameAndType
1716where
1717    T: Into<QualifiedName>,
1718{
1719    fn from(value: (T, &Type)) -> Self {
1720        let ty = value.1.to_owned();
1721        Self {
1722            name: value.0.into(),
1723            ty,
1724        }
1725    }
1726}
1727
1728impl CoreArrayProvider for QualifiedNameAndType {
1729    type Raw = BNQualifiedNameAndType;
1730    type Context = ();
1731    type Wrapped<'a> = Self;
1732}
1733
1734unsafe impl CoreArrayProviderInner for QualifiedNameAndType {
1735    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1736        BNFreeTypeAndNameList(raw, count);
1737    }
1738
1739    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1740        QualifiedNameAndType::from_raw(raw)
1741    }
1742}
1743
1744#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1745pub struct QualifiedNameTypeAndId {
1746    pub name: QualifiedName,
1747    pub ty: Ref<Type>,
1748    pub id: String,
1749}
1750
1751impl QualifiedNameTypeAndId {
1752    pub(crate) fn from_raw(value: &BNQualifiedNameTypeAndId) -> Self {
1753        Self {
1754            name: QualifiedName::from_raw(&value.name),
1755            ty: unsafe { Type::from_raw(value.type_) }.to_owned(),
1756            id: raw_to_string(value.id).unwrap(),
1757        }
1758    }
1759
1760    #[allow(unused)]
1761    pub(crate) fn from_owned_raw(value: BNQualifiedNameTypeAndId) -> Self {
1762        let owned = Self::from_raw(&value);
1763        Self::free_raw(value);
1764        owned
1765    }
1766
1767    pub(crate) fn into_raw(value: Self) -> BNQualifiedNameTypeAndId {
1768        let bn_id = BnString::new(value.id);
1769        BNQualifiedNameTypeAndId {
1770            name: QualifiedName::into_raw(value.name),
1771            id: BnString::into_raw(bn_id),
1772            type_: unsafe { Ref::into_raw(value.ty) }.handle,
1773        }
1774    }
1775
1776    pub(crate) fn free_raw(value: BNQualifiedNameTypeAndId) {
1777        QualifiedName::free_raw(value.name);
1778        let _ = unsafe { Type::ref_from_raw(value.type_) };
1779        let _ = unsafe { BnString::from_raw(value.id) };
1780    }
1781}
1782
1783impl CoreArrayProvider for QualifiedNameTypeAndId {
1784    type Raw = BNQualifiedNameTypeAndId;
1785    type Context = ();
1786    type Wrapped<'a> = QualifiedNameTypeAndId;
1787}
1788
1789unsafe impl CoreArrayProviderInner for QualifiedNameTypeAndId {
1790    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1791        BNFreeTypeIdList(raw, count);
1792    }
1793
1794    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1795        QualifiedNameTypeAndId::from_raw(raw)
1796    }
1797}
1798
1799// TODO: Document how this type is used for many different purposes. (this is literally (string, type))
1800// TODO: Ex. the name might be the parser it came from
1801// TODO: Ex. the name might be the param name for an intrinsic input
1802// TODO: Should we make new types for each varying use case?
1803#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1804pub struct NameAndType {
1805    pub name: String,
1806    pub ty: Conf<Ref<Type>>,
1807}
1808
1809impl NameAndType {
1810    pub(crate) fn from_raw(value: &BNNameAndType) -> Self {
1811        Self {
1812            // TODO: I dislike using this function here.
1813            name: raw_to_string(value.name as *mut _).unwrap(),
1814            ty: Conf::new(
1815                unsafe { Type::from_raw(value.type_).to_owned() },
1816                value.typeConfidence,
1817            ),
1818        }
1819    }
1820
1821    #[allow(unused)]
1822    pub(crate) fn from_owned_raw(value: BNNameAndType) -> Self {
1823        let owned = Self::from_raw(&value);
1824        Self::free_raw(value);
1825        owned
1826    }
1827
1828    pub(crate) fn into_raw(value: Self) -> BNNameAndType {
1829        let bn_name = BnString::new(value.name);
1830        BNNameAndType {
1831            name: BnString::into_raw(bn_name),
1832            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
1833            typeConfidence: value.ty.confidence,
1834        }
1835    }
1836
1837    pub(crate) fn free_raw(value: BNNameAndType) {
1838        unsafe { BnString::free_raw(value.name) };
1839        let _ = unsafe { Type::ref_from_raw(value.type_) };
1840    }
1841
1842    pub fn new(name: impl Into<String>, ty: Conf<Ref<Type>>) -> Self {
1843        Self {
1844            name: name.into(),
1845            ty,
1846        }
1847    }
1848}
1849
1850impl CoreArrayProvider for NameAndType {
1851    type Raw = BNNameAndType;
1852    type Context = ();
1853    type Wrapped<'a> = Self;
1854}
1855
1856unsafe impl CoreArrayProviderInner for NameAndType {
1857    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1858        BNFreeNameAndTypeList(raw, count);
1859    }
1860
1861    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1862        NameAndType::from_raw(raw)
1863    }
1864}