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