binaryninja/types/
structure.rs

1use crate::confidence::Conf;
2use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
3use crate::string::{raw_to_string, BnString, IntoCStr};
4use crate::types::{
5    MemberAccess, MemberScope, NamedTypeReference, StructureType, Type, TypeContainer,
6};
7use binaryninjacore_sys::*;
8use std::fmt::{Debug, Formatter};
9
10// Used for documentation purposes.
11#[allow(unused)]
12use crate::binary_view::BinaryView;
13
14#[derive(PartialEq, Eq, Hash)]
15pub struct StructureBuilder {
16    pub(crate) handle: *mut BNStructureBuilder,
17}
18
19/// ```no_run
20/// // Includes
21/// use binaryninja::types::{MemberAccess, MemberScope, Structure, StructureBuilder, Type};
22///
23/// // Types to use in the members
24/// let field_1_ty = Type::named_int(5, false, "my_weird_int_type");
25/// let field_2_ty = Type::int(4, false);
26/// let field_3_ty = Type::int(8, false);
27///
28/// // Assign those fields
29/// let mut my_custom_struct = StructureBuilder::new();
30/// my_custom_struct
31///     .insert(
32///         &field_1_ty,
33///         "field_1",
34///         0,
35///         false,
36///         MemberAccess::PublicAccess,
37///         MemberScope::NoScope,
38///     )
39///     .insert(
40///         &field_2_ty,
41///         "field_2",
42///         5,
43///         false,
44///         MemberAccess::PublicAccess,
45///         MemberScope::NoScope,
46///     )
47///     .insert(
48///         &field_3_ty,
49///         "field_3",
50///         9,
51///         false,
52///         MemberAccess::PublicAccess,
53///         MemberScope::NoScope,
54///     )
55///     .append(
56///         &field_1_ty,
57///         "field_4",
58///         MemberAccess::PublicAccess,
59///         MemberScope::NoScope,
60///     );
61///
62/// // Convert structure to type
63/// let my_custom_structure_type = Type::structure(&my_custom_struct.finalize());
64///
65/// // Add the struct to the binary view to use in analysis
66/// let bv = binaryninja::load("example").unwrap();
67/// bv.define_user_type("my_custom_struct", &my_custom_structure_type);
68/// ```
69impl StructureBuilder {
70    pub fn new() -> Self {
71        Self {
72            handle: unsafe { BNCreateStructureBuilder() },
73        }
74    }
75
76    pub(crate) unsafe fn from_raw(handle: *mut BNStructureBuilder) -> Self {
77        debug_assert!(!handle.is_null());
78        Self { handle }
79    }
80
81    // TODO: Document the width adjustment with alignment.
82    pub fn finalize(&self) -> Ref<Structure> {
83        let raw_struct_ptr = unsafe { BNFinalizeStructureBuilder(self.handle) };
84        unsafe { Structure::ref_from_raw(raw_struct_ptr) }
85    }
86
87    /// Sets the width of the [`StructureBuilder`] to the new width.
88    ///
89    /// This will remove all previously inserted members outside the new width. This is done by computing
90    /// the member access range (member offset + member width) and if it is larger than the new width
91    /// it will be removed.
92    pub fn width(&mut self, width: u64) -> &mut Self {
93        unsafe {
94            BNSetStructureBuilderWidth(self.handle, width);
95        }
96        self
97    }
98
99    pub fn alignment(&mut self, alignment: usize) -> &mut Self {
100        unsafe {
101            BNSetStructureBuilderAlignment(self.handle, alignment);
102        }
103        self
104    }
105
106    /// Sets whether the [`StructureBuilder`] is packed.
107    ///
108    /// If set the alignment of the structure will be `1`. You do not need to set the alignment to `1`.
109    pub fn packed(&mut self, packed: bool) -> &mut Self {
110        unsafe {
111            BNSetStructureBuilderPacked(self.handle, packed);
112        }
113        self
114    }
115
116    pub fn structure_type(&mut self, t: StructureType) -> &mut Self {
117        unsafe { BNSetStructureBuilderType(self.handle, t) };
118        self
119    }
120
121    pub fn pointer_offset(&mut self, offset: i64) -> &mut Self {
122        unsafe { BNSetStructureBuilderPointerOffset(self.handle, offset) };
123        self
124    }
125
126    pub fn propagates_data_var_refs(&mut self, propagates: bool) -> &mut Self {
127        unsafe { BNSetStructureBuilderPropagatesDataVariableReferences(self.handle, propagates) };
128        self
129    }
130
131    pub fn base_structures(&mut self, bases: &[BaseStructure]) -> &mut Self {
132        let raw_base_structs: Vec<BNBaseStructure> =
133            bases.iter().map(BaseStructure::into_owned_raw).collect();
134        unsafe {
135            BNSetBaseStructuresForStructureBuilder(
136                self.handle,
137                raw_base_structs.as_ptr() as *mut _,
138                raw_base_structs.len(),
139            )
140        };
141        self
142    }
143
144    /// Append a member at the next available byte offset.
145    ///
146    /// Otherwise, consider using:
147    ///
148    /// - [`StructureBuilder::insert_member`]
149    /// - [`StructureBuilder::insert`]
150    /// - [`StructureBuilder::insert_bitwise`]
151    pub fn append<'a, T: Into<Conf<&'a Type>>>(
152        &mut self,
153        ty: T,
154        name: &str,
155        access: MemberAccess,
156        scope: MemberScope,
157    ) -> &mut Self {
158        let name = name.to_cstr();
159        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
160        unsafe {
161            BNAddStructureBuilderMember(
162                self.handle,
163                &owned_raw_ty,
164                name.as_ref().as_ptr() as _,
165                access,
166                scope,
167            );
168        }
169        self
170    }
171
172    /// Insert an already constructed [`StructureMember`].
173    ///
174    /// Otherwise, consider using:
175    ///
176    /// - [`StructureBuilder::append`]
177    /// - [`StructureBuilder::insert`]
178    /// - [`StructureBuilder::insert_bitwise`]
179    pub fn insert_member(
180        &mut self,
181        member: StructureMember,
182        overwrite_existing: bool,
183    ) -> &mut Self {
184        self.insert_bitwise(
185            &member.ty,
186            &member.name,
187            member.bit_offset(),
188            member.bit_width,
189            overwrite_existing,
190            member.access,
191            member.scope,
192        );
193        self
194    }
195
196    /// Inserts a member at the `offset` (in bytes).
197    ///
198    /// If you need to insert a member at a specific bit within a given byte (like a bitfield), you
199    /// can use [`StructureBuilder::insert_bitwise`].
200    pub fn insert<'a, T: Into<Conf<&'a Type>>>(
201        &mut self,
202        ty: T,
203        name: &str,
204        offset: u64,
205        overwrite_existing: bool,
206        access: MemberAccess,
207        scope: MemberScope,
208    ) -> &mut Self {
209        self.insert_bitwise(
210            ty,
211            name,
212            offset * 8,
213            None,
214            overwrite_existing,
215            access,
216            scope,
217        )
218    }
219
220    /// Inserts a member at `bit_offset` with an optional `bit_width`.
221    ///
222    /// NOTE: The `bit_offset` is relative to the start of the structure, for example, passing `8` will place
223    /// the field at the start of the byte `0x1`.
224    pub fn insert_bitwise<'a, T: Into<Conf<&'a Type>>>(
225        &mut self,
226        ty: T,
227        name: &str,
228        bit_offset: u64,
229        bit_width: Option<u8>,
230        overwrite_existing: bool,
231        access: MemberAccess,
232        scope: MemberScope,
233    ) -> &mut Self {
234        let name = name.to_cstr();
235        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
236        let byte_offset = bit_offset / 8;
237        let bit_position = bit_offset % 8;
238        unsafe {
239            BNAddStructureBuilderMemberAtOffset(
240                self.handle,
241                &owned_raw_ty,
242                name.as_ref().as_ptr() as _,
243                byte_offset,
244                overwrite_existing,
245                access,
246                scope,
247                bit_position as u8,
248                bit_width.unwrap_or(0),
249            );
250        }
251        self
252    }
253
254    pub fn replace<'a, T: Into<Conf<&'a Type>>>(
255        &mut self,
256        index: usize,
257        ty: T,
258        name: &str,
259        overwrite_existing: bool,
260    ) -> &mut Self {
261        let name = name.to_cstr();
262        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
263        unsafe {
264            BNReplaceStructureBuilderMember(
265                self.handle,
266                index,
267                &owned_raw_ty,
268                name.as_ref().as_ptr() as _,
269                overwrite_existing,
270            )
271        }
272        self
273    }
274
275    /// Removes the member at a given index.
276    pub fn remove(&mut self, index: usize) -> &mut Self {
277        unsafe { BNRemoveStructureBuilderMember(self.handle, index) };
278        self
279    }
280
281    // TODO: We should add BNGetStructureBuilderAlignedWidth
282    /// Gets the current **unaligned** width of the structure.
283    ///
284    /// This cannot be used to accurately get the width of a non-packed structure.
285    pub fn current_width(&self) -> u64 {
286        unsafe { BNGetStructureBuilderWidth(self.handle) }
287    }
288}
289
290impl From<&Structure> for StructureBuilder {
291    fn from(structure: &Structure) -> StructureBuilder {
292        unsafe { Self::from_raw(BNCreateStructureBuilderFromStructure(structure.handle)) }
293    }
294}
295
296impl From<Vec<StructureMember>> for StructureBuilder {
297    fn from(members: Vec<StructureMember>) -> StructureBuilder {
298        let mut builder = StructureBuilder::new();
299        for member in members {
300            builder.insert_member(member, false);
301        }
302        builder
303    }
304}
305
306impl Drop for StructureBuilder {
307    fn drop(&mut self) {
308        unsafe { BNFreeStructureBuilder(self.handle) };
309    }
310}
311
312impl Default for StructureBuilder {
313    fn default() -> Self {
314        Self::new()
315    }
316}
317
318#[derive(PartialEq, Eq, Hash)]
319pub struct Structure {
320    pub(crate) handle: *mut BNStructure,
321}
322
323impl Structure {
324    pub(crate) unsafe fn ref_from_raw(handle: *mut BNStructure) -> Ref<Self> {
325        debug_assert!(!handle.is_null());
326        Ref::new(Self { handle })
327    }
328
329    pub fn builder() -> StructureBuilder {
330        StructureBuilder::new()
331    }
332
333    pub fn width(&self) -> u64 {
334        unsafe { BNGetStructureWidth(self.handle) }
335    }
336
337    pub fn structure_type(&self) -> StructureType {
338        unsafe { BNGetStructureType(self.handle) }
339    }
340
341    /// Retrieve the members that are accessible at a given offset.
342    ///
343    /// The reason for this being plural is that members may overlap and the offset is in bytes
344    /// where a bitfield may contain multiple members at the given byte.
345    ///
346    /// Unions are also represented as structures and will cause this function to return
347    /// **all** members that can reach that offset.
348    ///
349    /// We must pass a [`TypeContainer`] here so that we can resolve base structure members, as they
350    /// are treated as members through this function. Typically, you get the [`TypeContainer`]
351    /// through the binary view with [`BinaryView::type_container`].
352    pub fn members_at_offset(
353        &self,
354        container: &TypeContainer,
355        offset: u64,
356    ) -> Vec<StructureMember> {
357        self.members_including_inherited(container)
358            .into_iter()
359            .filter(|m| m.member.is_offset_valid(offset))
360            .map(|m| m.member)
361            .collect()
362    }
363
364    /// Return the list of non-inherited structure members.
365    ///
366    /// If you want to get all members, including ones inherited from base structures,
367    /// use [`Structure::members_including_inherited`] instead.
368    pub fn members(&self) -> Vec<StructureMember> {
369        unsafe {
370            let mut count = 0;
371            let members_raw_ptr: *mut BNStructureMember =
372                BNGetStructureMembers(self.handle, &mut count);
373            debug_assert!(!members_raw_ptr.is_null());
374            let members_raw = std::slice::from_raw_parts(members_raw_ptr, count);
375            let members = members_raw.iter().map(StructureMember::from_raw).collect();
376            BNFreeStructureMemberList(members_raw_ptr, count);
377            members
378        }
379    }
380
381    /// Returns the list of all structure members, including inherited ones.
382    ///
383    /// Because we must traverse through base structures, we have to provide the [`TypeContainer`];
384    /// in most cases it is ok to provide the binary views container via [`BinaryView::type_container`].
385    pub fn members_including_inherited(
386        &self,
387        container: &TypeContainer,
388    ) -> Vec<InheritedStructureMember> {
389        unsafe {
390            let mut count = 0;
391            let members_raw_ptr: *mut BNInheritedStructureMember =
392                BNGetStructureMembersIncludingInherited(
393                    self.handle,
394                    container.handle.as_ptr(),
395                    &mut count,
396                );
397            debug_assert!(!members_raw_ptr.is_null());
398            let members_raw = std::slice::from_raw_parts(members_raw_ptr, count);
399            let members = members_raw
400                .iter()
401                .map(InheritedStructureMember::from_raw)
402                .collect();
403            BNFreeInheritedStructureMemberList(members_raw_ptr, count);
404            members
405        }
406    }
407
408    /// Retrieve the list of base structures for the structure. These base structures are what give
409    /// a structure inherited members.
410    pub fn base_structures(&self) -> Vec<BaseStructure> {
411        let mut count = 0;
412        let bases_raw_ptr = unsafe { BNGetBaseStructuresForStructure(self.handle, &mut count) };
413        debug_assert!(!bases_raw_ptr.is_null());
414        let bases_raw = unsafe { std::slice::from_raw_parts(bases_raw_ptr, count) };
415        let bases = bases_raw.iter().map(BaseStructure::from_raw).collect();
416        unsafe { BNFreeBaseStructureList(bases_raw_ptr, count) };
417        bases
418    }
419
420    /// Whether the structure is packed or not.
421    pub fn is_packed(&self) -> bool {
422        unsafe { BNIsStructurePacked(self.handle) }
423    }
424
425    pub fn alignment(&self) -> usize {
426        unsafe { BNGetStructureAlignment(self.handle) }
427    }
428}
429
430impl Debug for Structure {
431    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
432        f.debug_struct("Structure")
433            .field("width", &self.width())
434            .field("alignment", &self.alignment())
435            .field("packed", &self.is_packed())
436            .field("structure_type", &self.structure_type())
437            .field("base_structures", &self.base_structures())
438            .field("members", &self.members())
439            .finish()
440    }
441}
442
443unsafe impl RefCountable for Structure {
444    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
445        Self::ref_from_raw(BNNewStructureReference(handle.handle))
446    }
447
448    unsafe fn dec_ref(handle: &Self) {
449        BNFreeStructure(handle.handle);
450    }
451}
452
453impl ToOwned for Structure {
454    type Owned = Ref<Self>;
455
456    fn to_owned(&self) -> Self::Owned {
457        unsafe { RefCountable::inc_ref(self) }
458    }
459}
460
461#[derive(Debug, Clone, Hash, PartialEq, Eq)]
462pub struct StructureMember {
463    pub ty: Conf<Ref<Type>>,
464    // TODO: Shouldnt this be a QualifiedName? The ffi says no...
465    pub name: String,
466    /// The byte offset of the member.
467    pub offset: u64,
468    pub access: MemberAccess,
469    pub scope: MemberScope,
470    /// The bit position relative to the byte offset.
471    pub bit_position: Option<u8>,
472    pub bit_width: Option<u8>,
473}
474
475impl StructureMember {
476    pub(crate) fn from_raw(value: &BNStructureMember) -> Self {
477        Self {
478            ty: Conf::new(
479                unsafe { Type::from_raw(value.type_) }.to_owned(),
480                value.typeConfidence,
481            ),
482            // TODO: I dislike using this function here.
483            name: raw_to_string(value.name as *mut _).unwrap(),
484            offset: value.offset,
485            access: value.access,
486            scope: value.scope,
487            bit_position: match value.bitPosition {
488                0 => None,
489                _ => Some(value.bitPosition),
490            },
491            bit_width: match value.bitWidth {
492                0 => None,
493                _ => Some(value.bitWidth),
494            },
495        }
496    }
497
498    #[allow(unused)]
499    pub(crate) fn from_owned_raw(value: BNStructureMember) -> Self {
500        let owned = Self::from_raw(&value);
501        Self::free_raw(value);
502        owned
503    }
504
505    #[allow(unused)]
506    pub(crate) fn into_raw(value: Self) -> BNStructureMember {
507        let bn_name = BnString::new(value.name);
508        BNStructureMember {
509            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
510            name: BnString::into_raw(bn_name),
511            offset: value.offset,
512            typeConfidence: value.ty.confidence,
513            access: value.access,
514            scope: value.scope,
515            bitPosition: value.bit_position.unwrap_or(0),
516            bitWidth: value.bit_width.unwrap_or(0),
517        }
518    }
519
520    #[allow(unused)]
521    pub(crate) fn free_raw(value: BNStructureMember) {
522        let _ = unsafe { Type::ref_from_raw(value.type_) };
523        unsafe { BnString::free_raw(value.name) };
524    }
525
526    pub fn new(
527        ty: Conf<Ref<Type>>,
528        name: String,
529        offset: u64,
530        access: MemberAccess,
531        scope: MemberScope,
532    ) -> Self {
533        Self {
534            ty,
535            name,
536            offset,
537            access,
538            scope,
539            bit_position: None,
540            bit_width: None,
541        }
542    }
543
544    pub fn new_bitfield(
545        ty: Conf<Ref<Type>>,
546        name: String,
547        bit_offset: u64,
548        bit_width: u8,
549        access: MemberAccess,
550        scope: MemberScope,
551    ) -> Self {
552        Self {
553            ty,
554            name,
555            offset: bit_offset / 8,
556            access,
557            scope,
558            bit_position: Some((bit_offset % 8) as u8),
559            bit_width: Some(bit_width),
560        }
561    }
562
563    // TODO: Do we count bitwidth here?
564    /// Whether the offset within the accessible range of the member.
565    pub fn is_offset_valid(&self, offset: u64) -> bool {
566        self.offset <= offset && offset < self.offset + self.ty.contents.width()
567    }
568
569    /// Member offset in bits.
570    pub fn bit_offset(&self) -> u64 {
571        (self.offset * 8) + self.bit_position.unwrap_or(0) as u64
572    }
573
574    /// Member width in bits.
575    ///
576    /// NOTE: This is a helper to calculate the bit width of the member, even for non-bitfield members.
577    /// This is not to be confused with the field `bit_width`, which is set for only bitfield members.
578    pub fn width_in_bits(&self) -> u64 {
579        self.bit_width
580            .map(|w| w as u64)
581            .unwrap_or(self.ty.contents.width() * 8)
582    }
583}
584
585impl CoreArrayProvider for StructureMember {
586    type Raw = BNStructureMember;
587    type Context = ();
588    type Wrapped<'a> = Self;
589}
590
591unsafe impl CoreArrayProviderInner for StructureMember {
592    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
593        BNFreeStructureMemberList(raw, count)
594    }
595
596    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
597        Self::from_raw(raw)
598    }
599}
600
601#[derive(Debug, Clone, Hash, PartialEq, Eq)]
602pub struct InheritedStructureMember {
603    pub base: Ref<NamedTypeReference>,
604    pub base_offset: u64,
605    pub member: StructureMember,
606    pub member_index: usize,
607}
608
609impl InheritedStructureMember {
610    pub(crate) fn from_raw(value: &BNInheritedStructureMember) -> Self {
611        Self {
612            base: unsafe { NamedTypeReference::from_raw(value.base) }.to_owned(),
613            base_offset: value.baseOffset,
614            member: StructureMember::from_raw(&value.member),
615            member_index: value.memberIndex,
616        }
617    }
618
619    #[allow(unused)]
620    pub(crate) fn from_owned_raw(value: BNInheritedStructureMember) -> Self {
621        let owned = Self::from_raw(&value);
622        Self::free_raw(value);
623        owned
624    }
625
626    #[allow(unused)]
627    pub(crate) fn into_raw(value: Self) -> BNInheritedStructureMember {
628        BNInheritedStructureMember {
629            base: unsafe { Ref::into_raw(value.base) }.handle,
630            baseOffset: value.base_offset,
631            member: StructureMember::into_raw(value.member),
632            memberIndex: value.member_index,
633        }
634    }
635
636    #[allow(unused)]
637    pub(crate) fn free_raw(value: BNInheritedStructureMember) {
638        let _ = unsafe { NamedTypeReference::ref_from_raw(value.base) };
639        StructureMember::free_raw(value.member);
640    }
641
642    pub fn new(
643        base: Ref<NamedTypeReference>,
644        base_offset: u64,
645        member: StructureMember,
646        member_index: usize,
647    ) -> Self {
648        Self {
649            base,
650            base_offset,
651            member,
652            member_index,
653        }
654    }
655}
656
657#[derive(Debug, Clone, Hash, PartialEq, Eq)]
658pub struct BaseStructure {
659    pub ty: Ref<NamedTypeReference>,
660    pub offset: u64,
661    pub width: u64,
662}
663
664impl BaseStructure {
665    pub(crate) fn from_raw(value: &BNBaseStructure) -> Self {
666        Self {
667            ty: unsafe { NamedTypeReference::from_raw(value.type_) }.to_owned(),
668            offset: value.offset,
669            width: value.width,
670        }
671    }
672
673    #[allow(unused)]
674    pub(crate) fn from_owned_raw(value: BNBaseStructure) -> Self {
675        let owned = Self::from_raw(&value);
676        Self::free_raw(value);
677        owned
678    }
679
680    #[allow(unused)]
681    pub(crate) fn into_raw(value: Self) -> BNBaseStructure {
682        BNBaseStructure {
683            type_: unsafe { Ref::into_raw(value.ty) }.handle,
684            offset: value.offset,
685            width: value.width,
686        }
687    }
688
689    pub(crate) fn into_owned_raw(value: &Self) -> BNBaseStructure {
690        BNBaseStructure {
691            type_: value.ty.handle,
692            offset: value.offset,
693            width: value.width,
694        }
695    }
696
697    #[allow(unused)]
698    pub(crate) fn free_raw(value: BNBaseStructure) {
699        let _ = unsafe { NamedTypeReference::ref_from_raw(value.type_) };
700    }
701
702    pub fn new(ty: Ref<NamedTypeReference>, offset: u64, width: u64) -> Self {
703        Self { ty, offset, width }
704    }
705}