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