binaryninja/
disassembly.rs

1// Copyright 2021-2025 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#![allow(unused)]
15
16use binaryninjacore_sys::*;
17
18use crate::architecture::Architecture;
19use crate::architecture::CoreArchitecture;
20use crate::basic_block::BasicBlock;
21use crate::function::{Location, NativeBlock};
22use crate::high_level_il as hlil;
23use crate::low_level_il as llil;
24use crate::medium_level_il as mlil;
25use crate::string::IntoCStr;
26use crate::string::{raw_to_string, strings_to_string_list, BnString};
27
28use crate::rc::*;
29
30use crate::confidence::MAX_CONFIDENCE;
31use crate::function::{Function, HighlightColor};
32use crate::tags::Tag;
33use crate::types::Type;
34use crate::variable::StackVariableReference;
35
36use crate::binary_view::StringType;
37use crate::high_level_il::HighLevelILFunction;
38use crate::low_level_il::function::{FunctionForm, FunctionMutability, LowLevelILFunction};
39use crate::medium_level_il::MediumLevelILFunction;
40use crate::project::Project;
41use std::convert::From;
42use std::ffi;
43use std::fmt::{Display, Formatter};
44use std::ptr;
45use std::ptr::NonNull;
46
47pub type DisassemblyOption = BNDisassemblyOption;
48pub type InstructionTextTokenType = BNInstructionTextTokenType;
49
50#[derive(Clone, PartialEq, Debug, Default, Eq)]
51pub struct DisassemblyTextLine {
52    pub address: u64,
53    // TODO: This is not always available.
54    pub instruction_index: usize,
55    pub tokens: Vec<InstructionTextToken>,
56    pub highlight: HighlightColor,
57    pub tags: Vec<Ref<Tag>>,
58    pub type_info: DisassemblyTextLineTypeInfo,
59}
60
61impl DisassemblyTextLine {
62    pub(crate) fn from_raw(value: &BNDisassemblyTextLine) -> Self {
63        let raw_tokens = unsafe { std::slice::from_raw_parts(value.tokens, value.count) };
64        let tokens: Vec<_> = raw_tokens
65            .iter()
66            .map(InstructionTextToken::from_raw)
67            .collect();
68        // SAFETY: Increment the tag ref as we are going from ref to owned.
69        let raw_tags = unsafe { std::slice::from_raw_parts(value.tags, value.tagCount) };
70        let tags: Vec<_> = raw_tags
71            .iter()
72            .map(|&t| unsafe { Tag::from_raw(t) }.to_owned())
73            .collect();
74        Self {
75            address: value.addr,
76            instruction_index: value.instrIndex,
77            tokens,
78            highlight: value.highlight.into(),
79            tags,
80            type_info: DisassemblyTextLineTypeInfo::from_raw(&value.typeInfo),
81        }
82    }
83
84    /// Convert into a raw [BNDisassemblyTextLine], use with caution.
85    ///
86    /// NOTE: The allocations here for tokens and tags MUST be freed by rust using [Self::free_raw].
87    pub(crate) fn into_raw(value: Self) -> BNDisassemblyTextLine {
88        // NOTE: The instruction text and type names fields are being leaked here. To be freed with [Self::free_raw].
89        let tokens: Box<[BNInstructionTextToken]> = value
90            .tokens
91            .into_iter()
92            .map(InstructionTextToken::into_raw)
93            .collect();
94        let tags: Box<[*mut BNTag]> = value
95            .tags
96            .into_iter()
97            .map(|t| {
98                // SAFETY: The tags ref will be temporarily incremented here, until [Self::free_raw] is called.
99                // SAFETY: This is so that tags lifetime is long enough, as we might be the last holders of the ref.
100                unsafe { Ref::into_raw(t) }.handle
101            })
102            .collect();
103        BNDisassemblyTextLine {
104            addr: value.address,
105            instrIndex: value.instruction_index,
106            count: tokens.len(),
107            // NOTE: Leaking tokens here to be freed with [Self::free_raw].
108            tokens: Box::leak(tokens).as_mut_ptr(),
109            highlight: value.highlight.into(),
110            tagCount: tags.len(),
111            // NOTE: Leaking tags here to be freed with [Self::free_raw].
112            tags: Box::leak(tags).as_mut_ptr(),
113            typeInfo: DisassemblyTextLineTypeInfo::into_raw(value.type_info),
114        }
115    }
116
117    /// Frees raw object created with [Self::into_raw], use with caution.
118    ///
119    /// NOTE: The allocations freed MUST have been created in rust using [Self::into_raw].
120    pub(crate) fn free_raw(value: BNDisassemblyTextLine) {
121        // Free the token list
122        let raw_tokens = unsafe { std::slice::from_raw_parts_mut(value.tokens, value.count) };
123        let boxed_tokens = unsafe { Box::from_raw(raw_tokens) };
124        for token in boxed_tokens {
125            // SAFETY: As we have leaked the token contents we need to now free them (text and typeNames).
126            InstructionTextToken::free_raw(token);
127        }
128        // Free the tag list
129        let raw_tags = unsafe { std::slice::from_raw_parts_mut(value.tags, value.tagCount) };
130        let boxed_tags = unsafe { Box::from_raw(raw_tags) };
131        for tag in boxed_tags {
132            // SAFETY: As we have incremented the tags ref in [Self::into_raw] we must now decrement.
133            let _ = unsafe { Tag::ref_from_raw(tag) };
134        }
135        // Free the type info
136        DisassemblyTextLineTypeInfo::free_raw(value.typeInfo);
137    }
138
139    pub fn new(tokens: Vec<InstructionTextToken>) -> Self {
140        Self {
141            tokens,
142            ..Default::default()
143        }
144    }
145
146    pub fn new_with_addr(tokens: Vec<InstructionTextToken>, addr: u64) -> Self {
147        Self {
148            address: addr,
149            tokens,
150            ..Default::default()
151        }
152    }
153}
154
155impl From<&str> for DisassemblyTextLine {
156    fn from(value: &str) -> Self {
157        Self::new(vec![InstructionTextToken::new(
158            value,
159            InstructionTextTokenKind::Text,
160        )])
161    }
162}
163
164impl From<String> for DisassemblyTextLine {
165    fn from(value: String) -> Self {
166        Self::new(vec![InstructionTextToken::new(
167            value,
168            InstructionTextTokenKind::Text,
169        )])
170    }
171}
172
173impl Display for DisassemblyTextLine {
174    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
175        for token in &self.tokens {
176            write!(f, "{}", token)?;
177        }
178        Ok(())
179    }
180}
181
182impl CoreArrayProvider for DisassemblyTextLine {
183    type Raw = BNDisassemblyTextLine;
184    type Context = ();
185    type Wrapped<'a> = Self;
186}
187
188unsafe impl CoreArrayProviderInner for DisassemblyTextLine {
189    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
190        BNFreeDisassemblyTextLines(raw, count)
191    }
192
193    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
194        Self::from_raw(raw)
195    }
196}
197
198#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
199pub struct DisassemblyTextLineTypeInfo {
200    pub has_type_info: bool,
201    pub parent_type: Option<Ref<Type>>,
202    pub field_index: usize,
203    pub offset: u64,
204}
205
206impl DisassemblyTextLineTypeInfo {
207    pub(crate) fn from_raw(value: &BNDisassemblyTextLineTypeInfo) -> Self {
208        Self {
209            has_type_info: value.hasTypeInfo,
210            parent_type: match value.parentType.is_null() {
211                false => Some(unsafe { Type::from_raw(value.parentType).to_owned() }),
212                true => None,
213            },
214            field_index: value.fieldIndex,
215            offset: value.offset,
216        }
217    }
218
219    pub(crate) fn from_owned_raw(value: BNDisassemblyTextLineTypeInfo) -> Self {
220        Self {
221            has_type_info: value.hasTypeInfo,
222            parent_type: match value.parentType.is_null() {
223                false => Some(unsafe { Type::ref_from_raw(value.parentType) }),
224                true => None,
225            },
226            field_index: value.fieldIndex,
227            offset: value.offset,
228        }
229    }
230
231    pub(crate) fn into_raw(value: Self) -> BNDisassemblyTextLineTypeInfo {
232        BNDisassemblyTextLineTypeInfo {
233            hasTypeInfo: value.has_type_info,
234            parentType: value
235                .parent_type
236                .map(|t| unsafe { Ref::into_raw(t) }.handle)
237                .unwrap_or(std::ptr::null_mut()),
238            fieldIndex: value.field_index,
239            offset: value.offset,
240        }
241    }
242
243    pub(crate) fn into_owned_raw(value: &Self) -> BNDisassemblyTextLineTypeInfo {
244        BNDisassemblyTextLineTypeInfo {
245            hasTypeInfo: value.has_type_info,
246            parentType: value
247                .parent_type
248                .as_ref()
249                .map(|t| t.handle)
250                .unwrap_or(std::ptr::null_mut()),
251            fieldIndex: value.field_index,
252            offset: value.offset,
253        }
254    }
255
256    pub(crate) fn free_raw(value: BNDisassemblyTextLineTypeInfo) {
257        if !value.parentType.is_null() {
258            let _ = unsafe { Type::ref_from_raw(value.parentType) };
259        }
260    }
261}
262
263#[derive(Debug, Clone, PartialEq, Eq)]
264pub struct InstructionTextToken {
265    pub address: u64,
266    pub text: String,
267    pub confidence: u8,
268    pub context: InstructionTextTokenContext,
269    // TODO: Document that this is not necessary to set and that this is valid in a limited context.
270    pub expr_index: usize,
271    pub kind: InstructionTextTokenKind,
272}
273
274impl InstructionTextToken {
275    pub(crate) fn from_raw(value: &BNInstructionTextToken) -> Self {
276        Self {
277            address: value.address,
278            text: raw_to_string(value.text).unwrap(),
279            confidence: value.confidence,
280            context: value.context.into(),
281            expr_index: value.exprIndex,
282            kind: InstructionTextTokenKind::from_raw(value),
283        }
284    }
285
286    pub(crate) fn into_raw(value: Self) -> BNInstructionTextToken {
287        let bn_text = BnString::new(value.text);
288        // These can be gathered from value.kind
289        let kind_value = value.kind.try_value().unwrap_or(0);
290        let operand = value.kind.try_operand().unwrap_or(0);
291        let size = value.kind.try_size().unwrap_or(0);
292        let type_names = value.kind.try_type_names().unwrap_or_default();
293        BNInstructionTextToken {
294            type_: value.kind.into(),
295            // NOTE: Expected to be freed with `InstructionTextToken::free_raw`.
296            text: BnString::into_raw(bn_text),
297            value: kind_value,
298            // TODO: Where is this even used?
299            width: 0,
300            size,
301            operand,
302            context: value.context.into(),
303            confidence: value.confidence,
304            address: value.address,
305            // NOTE: Expected to be freed with `InstructionTextToken::free_raw`.
306            typeNames: strings_to_string_list(&type_names),
307            namesCount: type_names.len(),
308            exprIndex: value.expr_index,
309        }
310    }
311
312    pub(crate) fn free_raw(value: BNInstructionTextToken) {
313        unsafe { BnString::free_raw(value.text) };
314        if !value.typeNames.is_null() {
315            unsafe { BNFreeStringList(value.typeNames, value.namesCount) };
316        }
317    }
318
319    /// Construct a new token **without** an associated address.
320    ///
321    /// You most likely want to call [`InstructionTextToken::new_with_address`], while also adjusting
322    /// the [`InstructionTextToken::expr_index`] field where applicable.
323    pub fn new(text: impl Into<String>, kind: InstructionTextTokenKind) -> Self {
324        Self {
325            address: 0,
326            text: text.into(),
327            confidence: MAX_CONFIDENCE,
328            context: InstructionTextTokenContext::Normal,
329            expr_index: 0,
330            kind,
331        }
332    }
333
334    pub fn new_with_address(
335        address: u64,
336        text: impl Into<String>,
337        kind: InstructionTextTokenKind,
338    ) -> Self {
339        Self {
340            address,
341            text: text.into(),
342            confidence: MAX_CONFIDENCE,
343            context: InstructionTextTokenContext::Normal,
344            expr_index: 0,
345            kind,
346        }
347    }
348}
349
350impl Display for InstructionTextToken {
351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352        self.text.fmt(f)
353    }
354}
355
356impl CoreArrayProvider for InstructionTextToken {
357    type Raw = BNInstructionTextToken;
358    type Context = ();
359    type Wrapped<'a> = Self;
360}
361
362unsafe impl CoreArrayProviderInner for InstructionTextToken {
363    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
364        // SAFETY: The Array MUST have been allocated on the core side. This will `delete[] raw`.
365        BNFreeInstructionText(raw, count)
366    }
367
368    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
369        Self::from_raw(raw)
370    }
371}
372
373impl CoreArrayProvider for Array<InstructionTextToken> {
374    type Raw = BNInstructionTextLine;
375    type Context = ();
376    type Wrapped<'a> = std::mem::ManuallyDrop<Self>;
377}
378
379unsafe impl CoreArrayProviderInner for Array<InstructionTextToken> {
380    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
381        // SAFETY: The Array MUST have been allocated on the core side. This will `delete[] raw`.
382        BNFreeInstructionTextLines(raw, count)
383    }
384
385    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
386        // TODO: This is insane.
387        std::mem::ManuallyDrop::new(Self::new(raw.tokens, raw.count, ()))
388    }
389}
390
391#[derive(Clone, PartialEq, Debug)]
392pub enum InstructionTextTokenKind {
393    Text,
394    Instruction,
395    OperandSeparator,
396    Register,
397    Integer {
398        value: u64,
399        /// Size of the integer
400        size: Option<usize>,
401    },
402    PossibleAddress {
403        value: u64,
404        /// Size of the address
405        size: Option<usize>,
406    },
407    BeginMemoryOperand,
408    EndMemoryOperand,
409    FloatingPoint {
410        value: f64,
411        /// Size of the floating point
412        size: Option<usize>,
413    },
414    Annotation,
415    CodeRelativeAddress {
416        value: u64,
417        size: Option<usize>,
418    },
419    ArgumentName {
420        // TODO: The argument index?
421        value: u64,
422    },
423    HexDumpByteValue {
424        value: u8,
425    },
426    HexDumpSkippedByte,
427    HexDumpInvalidByte,
428    HexDumpText {
429        // TODO: Explain what this does
430        width: u64,
431    },
432    Opcode,
433    String {
434        // TODO: What is this?
435        // TODO: It seems like people just throw things in here...
436        value: u64,
437    },
438    /// String content is only present for:
439    /// - [`InstructionTextTokenContext::StringReference`]
440    /// - [`InstructionTextTokenContext::StringDisplay`]
441    StringContent {
442        ty: StringType,
443    },
444    CharacterConstant,
445    Keyword {
446        // Example usage can be found for `BNAnalysisWarningActionType`.
447        value: u64,
448    },
449    TypeName,
450    FieldName {
451        /// Offset to this field in the respective structure
452        offset: u64,
453        /// Stores the type names for the referenced field name.
454        ///
455        /// This is typically just the members name.
456        /// For example MyStructure.my_field will have type_names be \["my_field"\].
457        type_names: Vec<String>,
458    },
459    NameSpace,
460    NameSpaceSeparator,
461    Tag,
462    StructOffset {
463        /// Offset to this field in the respective structure
464        offset: u64,
465        // TODO: This makes no sense for struct offset, they dont have types?
466        /// Stores the type names for the referenced field name.
467        type_names: Vec<String>,
468    },
469    // TODO: Unused?
470    StructOffsetByteValue,
471    // TODO: Unused?
472    StructureHexDumpText {
473        // TODO: Explain what this does
474        width: u64,
475    },
476    GotoLabel {
477        target: u64,
478    },
479    Comment {
480        target: u64,
481    },
482    PossibleValue {
483        value: u64,
484    },
485    // TODO: This is weird, you pass the value type as the text, we should restrict this behavior and type it
486    PossibleValueType,
487    ArrayIndex {
488        index: u64,
489    },
490    Indentation,
491    UnknownMemory,
492    EnumerationMember {
493        value: u64,
494        // TODO: Document where this type id comes from
495        // TODO: Can we type this to something other than a string?
496        /// The enumerations type id
497        type_id: Option<String>,
498    },
499    /// Operations like +, -, %
500    Operation,
501    BaseStructureName,
502    BaseStructureSeparator,
503    Brace {
504        // TODO: Explain what this is
505        hash: Option<u64>,
506    },
507    CodeSymbol {
508        // Target address of the symbol
509        value: u64,
510        // TODO: Size of what?
511        size: usize, // TODO: Operand?
512    },
513    DataSymbol {
514        // Target address of the symbol
515        value: u64,
516        // TODO: Size of what?
517        size: usize, // TODO: Operand?
518    },
519    LocalVariable {
520        // This comes from the token.value
521        // TODO: Do we have a variable id type we can attach to this?
522        // TODO: Probably not considering this is used at multiple IL levels.
523        variable_id: u64,
524        /// NOTE: This is only valid in SSA form
525        ssa_version: usize,
526    },
527    Import {
528        // TODO: Looks to be the target address from the import.
529        target: u64,
530    },
531    AddressDisplay {
532        address: u64,
533    },
534    // TODO: BAD
535    IndirectImport {
536        /// The address of the import
537        ///
538        /// If you want the address of the import token use [`InstructionTextToken::address`] instead.
539        target: u64,
540        /// Size of the instruction this token is apart of
541        size: usize,
542        // TODO: Type this
543        source_operand: usize,
544    },
545    ExternalSymbol {
546        // TODO: Value of what?
547        value: u64,
548    },
549    StackVariable {
550        // TODO: Do we have a variable id type we can attach to this?
551        // TODO: Probably not considering this is used at multiple IL levels.
552        variable_id: u64,
553    },
554    AddressSeparator,
555    CollapsedInformation,
556    CollapseStateIndicator {
557        // TODO: Explain what this is
558        hash: Option<u64>,
559    },
560    NewLine {
561        // Offset into instruction that this new line is associated with
562        value: u64,
563    },
564}
565
566impl InstructionTextTokenKind {
567    pub(crate) fn from_raw(value: &BNInstructionTextToken) -> Self {
568        match value.type_ {
569            BNInstructionTextTokenType::TextToken => Self::Text,
570            BNInstructionTextTokenType::InstructionToken => Self::Instruction,
571            BNInstructionTextTokenType::OperandSeparatorToken => Self::OperandSeparator,
572            BNInstructionTextTokenType::RegisterToken => Self::Register,
573            BNInstructionTextTokenType::IntegerToken => Self::Integer {
574                value: value.value,
575                size: match value.size {
576                    0 => None,
577                    size => Some(size),
578                },
579            },
580            BNInstructionTextTokenType::PossibleAddressToken => Self::PossibleAddress {
581                value: value.value,
582                size: match value.size {
583                    0 => None,
584                    size => Some(size),
585                },
586            },
587            BNInstructionTextTokenType::BeginMemoryOperandToken => Self::BeginMemoryOperand,
588            BNInstructionTextTokenType::EndMemoryOperandToken => Self::EndMemoryOperand,
589            BNInstructionTextTokenType::FloatingPointToken => Self::FloatingPoint {
590                value: value.value as f64,
591                size: match value.size {
592                    0 => None,
593                    size => Some(size),
594                },
595            },
596            BNInstructionTextTokenType::AnnotationToken => Self::Annotation,
597            BNInstructionTextTokenType::CodeRelativeAddressToken => Self::CodeRelativeAddress {
598                value: value.value,
599                size: match value.size {
600                    0 => None,
601                    size => Some(size),
602                },
603            },
604            BNInstructionTextTokenType::ArgumentNameToken => {
605                Self::ArgumentName { value: value.value }
606            }
607            BNInstructionTextTokenType::HexDumpByteValueToken => Self::HexDumpByteValue {
608                value: value.value as u8,
609            },
610            BNInstructionTextTokenType::HexDumpSkippedByteToken => Self::HexDumpSkippedByte,
611            BNInstructionTextTokenType::HexDumpInvalidByteToken => Self::HexDumpInvalidByte,
612            BNInstructionTextTokenType::HexDumpTextToken => {
613                Self::HexDumpText { width: value.value }
614            }
615            BNInstructionTextTokenType::OpcodeToken => Self::Opcode,
616            BNInstructionTextTokenType::StringToken => match value.context {
617                BNInstructionTextTokenContext::StringReferenceTokenContext
618                | BNInstructionTextTokenContext::StringDisplayTokenContext => {
619                    match value.value {
620                        0 => Self::StringContent {
621                            ty: StringType::AsciiString,
622                        },
623                        1 => Self::StringContent {
624                            ty: StringType::Utf8String,
625                        },
626                        2 => Self::StringContent {
627                            ty: StringType::Utf16String,
628                        },
629                        3 => Self::StringContent {
630                            ty: StringType::Utf32String,
631                        },
632                        // If we reach here all hope is lost.
633                        // Reaching here means someone made a ref or display context token with no
634                        // StringType and instead some other random value...
635                        value => Self::String { value },
636                    }
637                }
638                _ => Self::String { value: value.value },
639            },
640            BNInstructionTextTokenType::CharacterConstantToken => Self::CharacterConstant,
641            BNInstructionTextTokenType::KeywordToken => Self::Keyword { value: value.value },
642            BNInstructionTextTokenType::TypeNameToken => Self::TypeName,
643            BNInstructionTextTokenType::FieldNameToken => Self::FieldName {
644                offset: value.value,
645                type_names: {
646                    // NOTE: Do not need to free, this is a part of the From<&> impl
647                    let raw_names =
648                        unsafe { std::slice::from_raw_parts(value.typeNames, value.namesCount) };
649                    raw_names.iter().filter_map(|&r| raw_to_string(r)).collect()
650                },
651            },
652            BNInstructionTextTokenType::NameSpaceToken => Self::NameSpace,
653            BNInstructionTextTokenType::NameSpaceSeparatorToken => Self::NameSpaceSeparator,
654            BNInstructionTextTokenType::TagToken => Self::Tag,
655            BNInstructionTextTokenType::StructOffsetToken => Self::StructOffset {
656                offset: value.value,
657                type_names: {
658                    // NOTE: Do not need to free, this is a part of the From<&> impl
659                    let raw_names =
660                        unsafe { std::slice::from_raw_parts(value.typeNames, value.namesCount) };
661                    raw_names.iter().filter_map(|&r| raw_to_string(r)).collect()
662                },
663            },
664            BNInstructionTextTokenType::StructOffsetByteValueToken => Self::StructOffsetByteValue,
665            BNInstructionTextTokenType::StructureHexDumpTextToken => {
666                Self::StructureHexDumpText { width: value.value }
667            }
668            BNInstructionTextTokenType::GotoLabelToken => Self::GotoLabel {
669                target: value.value,
670            },
671            BNInstructionTextTokenType::CommentToken => Self::Comment {
672                target: value.value,
673            },
674            BNInstructionTextTokenType::PossibleValueToken => {
675                Self::PossibleValue { value: value.value }
676            }
677            // NOTE: See my comment about this type in [`Self::PossibleValueType`]
678            BNInstructionTextTokenType::PossibleValueTypeToken => Self::PossibleValueType,
679            BNInstructionTextTokenType::ArrayIndexToken => Self::ArrayIndex { index: value.value },
680            BNInstructionTextTokenType::IndentationToken => Self::Indentation,
681            BNInstructionTextTokenType::UnknownMemoryToken => Self::UnknownMemory,
682            BNInstructionTextTokenType::EnumerationMemberToken => Self::EnumerationMember {
683                value: value.value,
684                type_id: {
685                    // NOTE: Type id comes from value.typeNames, it should be the first one (hence the .next)
686                    // NOTE: Do not need to free, this is a part of the From<&> impl
687                    let raw_names =
688                        unsafe { std::slice::from_raw_parts(value.typeNames, value.namesCount) };
689                    raw_names.iter().filter_map(|&r| raw_to_string(r)).next()
690                },
691            },
692            BNInstructionTextTokenType::OperationToken => Self::Operation,
693            BNInstructionTextTokenType::BaseStructureNameToken => Self::BaseStructureName,
694            BNInstructionTextTokenType::BaseStructureSeparatorToken => Self::BaseStructureSeparator,
695            BNInstructionTextTokenType::BraceToken => Self::Brace {
696                hash: match value.value {
697                    0 => None,
698                    hash => Some(hash),
699                },
700            },
701            BNInstructionTextTokenType::CodeSymbolToken => Self::CodeSymbol {
702                value: value.value,
703                size: value.size,
704            },
705            BNInstructionTextTokenType::DataSymbolToken => Self::DataSymbol {
706                value: value.value,
707                size: value.size,
708            },
709            BNInstructionTextTokenType::LocalVariableToken => Self::LocalVariable {
710                variable_id: value.value,
711                ssa_version: value.operand,
712            },
713            BNInstructionTextTokenType::ImportToken => Self::Import {
714                target: value.value,
715            },
716            BNInstructionTextTokenType::AddressDisplayToken => Self::AddressDisplay {
717                address: value.value,
718            },
719            BNInstructionTextTokenType::IndirectImportToken => Self::IndirectImport {
720                target: value.value,
721                size: value.size,
722                source_operand: value.operand,
723            },
724            BNInstructionTextTokenType::ExternalSymbolToken => {
725                Self::ExternalSymbol { value: value.value }
726            }
727            BNInstructionTextTokenType::StackVariableToken => Self::StackVariable {
728                variable_id: value.value,
729            },
730            BNInstructionTextTokenType::AddressSeparatorToken => Self::AddressSeparator,
731            BNInstructionTextTokenType::CollapsedInformationToken => Self::CollapsedInformation,
732            BNInstructionTextTokenType::CollapseStateIndicatorToken => {
733                Self::CollapseStateIndicator {
734                    hash: match value.value {
735                        0 => None,
736                        hash => Some(hash),
737                    },
738                }
739            }
740            BNInstructionTextTokenType::NewLineToken => Self::NewLine { value: value.value },
741        }
742    }
743
744    /// Mapping to the [`BNInstructionTextTokenType::value`] field.
745    fn try_value(&self) -> Option<u64> {
746        // TODO: Double check to make sure these are correct.
747        match self {
748            InstructionTextTokenKind::Integer { value, .. } => Some(*value),
749            InstructionTextTokenKind::PossibleAddress { value, .. } => Some(*value),
750            InstructionTextTokenKind::PossibleValue { value, .. } => Some(*value),
751            InstructionTextTokenKind::FloatingPoint { value, .. } => Some(*value as u64),
752            InstructionTextTokenKind::CodeRelativeAddress { value, .. } => Some(*value),
753            InstructionTextTokenKind::ArgumentName { value, .. } => Some(*value),
754            InstructionTextTokenKind::HexDumpByteValue { value, .. } => Some(*value as u64),
755            InstructionTextTokenKind::HexDumpText { width, .. } => Some(*width),
756            InstructionTextTokenKind::String { value, .. } => Some(*value),
757            InstructionTextTokenKind::StringContent { ty, .. } => Some(*ty as u64),
758            InstructionTextTokenKind::Keyword { value, .. } => Some(*value),
759            InstructionTextTokenKind::FieldName { offset, .. } => Some(*offset),
760            InstructionTextTokenKind::StructOffset { offset, .. } => Some(*offset),
761            InstructionTextTokenKind::StructureHexDumpText { width, .. } => Some(*width),
762            InstructionTextTokenKind::GotoLabel { target, .. } => Some(*target),
763            InstructionTextTokenKind::Comment { target, .. } => Some(*target),
764            InstructionTextTokenKind::ArrayIndex { index, .. } => Some(*index),
765            InstructionTextTokenKind::EnumerationMember { value, .. } => Some(*value),
766            InstructionTextTokenKind::LocalVariable { variable_id, .. } => Some(*variable_id),
767            InstructionTextTokenKind::Import { target, .. } => Some(*target),
768            InstructionTextTokenKind::AddressDisplay { address, .. } => Some(*address),
769            InstructionTextTokenKind::IndirectImport { target, .. } => Some(*target),
770            InstructionTextTokenKind::Brace { hash, .. } => *hash,
771            InstructionTextTokenKind::CodeSymbol { value, .. } => Some(*value),
772            InstructionTextTokenKind::DataSymbol { value, .. } => Some(*value),
773            InstructionTextTokenKind::ExternalSymbol { value, .. } => Some(*value),
774            InstructionTextTokenKind::StackVariable { variable_id, .. } => Some(*variable_id),
775            InstructionTextTokenKind::CollapseStateIndicator { hash, .. } => *hash,
776            InstructionTextTokenKind::NewLine { value, .. } => Some(*value),
777            _ => None,
778        }
779    }
780
781    /// Mapping to the [`BNInstructionTextTokenType::size`] field.
782    fn try_size(&self) -> Option<usize> {
783        match self {
784            InstructionTextTokenKind::Integer { size, .. } => *size,
785            InstructionTextTokenKind::FloatingPoint { size, .. } => *size,
786            InstructionTextTokenKind::PossibleAddress { size, .. } => *size,
787            InstructionTextTokenKind::CodeRelativeAddress { size, .. } => *size,
788            InstructionTextTokenKind::CodeSymbol { size, .. } => Some(*size),
789            InstructionTextTokenKind::DataSymbol { size, .. } => Some(*size),
790            InstructionTextTokenKind::IndirectImport { size, .. } => Some(*size),
791            _ => None,
792        }
793    }
794
795    /// Mapping to the [`BNInstructionTextTokenType::operand`] field.
796    fn try_operand(&self) -> Option<usize> {
797        match self {
798            InstructionTextTokenKind::LocalVariable { ssa_version, .. } => Some(*ssa_version),
799            InstructionTextTokenKind::IndirectImport { source_operand, .. } => {
800                Some(*source_operand)
801            }
802            _ => None,
803        }
804    }
805
806    /// Mapping to the [`BNInstructionTextTokenType::typeNames`] field.
807    fn try_type_names(&self) -> Option<Vec<String>> {
808        match self {
809            InstructionTextTokenKind::FieldName { type_names, .. } => Some(type_names.clone()),
810            InstructionTextTokenKind::StructOffset { type_names, .. } => Some(type_names.clone()),
811            InstructionTextTokenKind::EnumerationMember { type_id, .. } => {
812                Some(vec![type_id.clone()?])
813            }
814            _ => None,
815        }
816    }
817}
818
819impl From<InstructionTextTokenKind> for BNInstructionTextTokenType {
820    fn from(value: InstructionTextTokenKind) -> Self {
821        match value {
822            InstructionTextTokenKind::Text => BNInstructionTextTokenType::TextToken,
823            InstructionTextTokenKind::Instruction => BNInstructionTextTokenType::InstructionToken,
824            InstructionTextTokenKind::OperandSeparator => {
825                BNInstructionTextTokenType::OperandSeparatorToken
826            }
827            InstructionTextTokenKind::Register => BNInstructionTextTokenType::RegisterToken,
828            InstructionTextTokenKind::Integer { .. } => BNInstructionTextTokenType::IntegerToken,
829            InstructionTextTokenKind::PossibleAddress { .. } => {
830                BNInstructionTextTokenType::PossibleAddressToken
831            }
832            InstructionTextTokenKind::BeginMemoryOperand => {
833                BNInstructionTextTokenType::BeginMemoryOperandToken
834            }
835            InstructionTextTokenKind::EndMemoryOperand => {
836                BNInstructionTextTokenType::EndMemoryOperandToken
837            }
838            InstructionTextTokenKind::FloatingPoint { .. } => {
839                BNInstructionTextTokenType::FloatingPointToken
840            }
841            InstructionTextTokenKind::Annotation => BNInstructionTextTokenType::AnnotationToken,
842            InstructionTextTokenKind::CodeRelativeAddress { .. } => {
843                BNInstructionTextTokenType::CodeRelativeAddressToken
844            }
845            InstructionTextTokenKind::ArgumentName { .. } => {
846                BNInstructionTextTokenType::ArgumentNameToken
847            }
848            InstructionTextTokenKind::HexDumpByteValue { .. } => {
849                BNInstructionTextTokenType::HexDumpByteValueToken
850            }
851            InstructionTextTokenKind::HexDumpSkippedByte => {
852                BNInstructionTextTokenType::HexDumpSkippedByteToken
853            }
854            InstructionTextTokenKind::HexDumpInvalidByte => {
855                BNInstructionTextTokenType::HexDumpInvalidByteToken
856            }
857            InstructionTextTokenKind::HexDumpText { .. } => {
858                BNInstructionTextTokenType::HexDumpTextToken
859            }
860            InstructionTextTokenKind::Opcode => BNInstructionTextTokenType::OpcodeToken,
861            InstructionTextTokenKind::String { .. } => BNInstructionTextTokenType::StringToken,
862            InstructionTextTokenKind::StringContent { .. } => {
863                BNInstructionTextTokenType::StringToken
864            }
865            InstructionTextTokenKind::CharacterConstant => {
866                BNInstructionTextTokenType::CharacterConstantToken
867            }
868            InstructionTextTokenKind::Keyword { .. } => BNInstructionTextTokenType::KeywordToken,
869            InstructionTextTokenKind::TypeName => BNInstructionTextTokenType::TypeNameToken,
870            InstructionTextTokenKind::FieldName { .. } => {
871                BNInstructionTextTokenType::FieldNameToken
872            }
873            InstructionTextTokenKind::NameSpace => BNInstructionTextTokenType::NameSpaceToken,
874            InstructionTextTokenKind::NameSpaceSeparator => {
875                BNInstructionTextTokenType::NameSpaceSeparatorToken
876            }
877            InstructionTextTokenKind::Tag => BNInstructionTextTokenType::TagToken,
878            InstructionTextTokenKind::StructOffset { .. } => {
879                BNInstructionTextTokenType::StructOffsetToken
880            }
881            InstructionTextTokenKind::StructOffsetByteValue => {
882                BNInstructionTextTokenType::StructOffsetByteValueToken
883            }
884            InstructionTextTokenKind::StructureHexDumpText { .. } => {
885                BNInstructionTextTokenType::StructureHexDumpTextToken
886            }
887            InstructionTextTokenKind::GotoLabel { .. } => {
888                BNInstructionTextTokenType::GotoLabelToken
889            }
890            InstructionTextTokenKind::Comment { .. } => BNInstructionTextTokenType::CommentToken,
891            InstructionTextTokenKind::PossibleValue { .. } => {
892                BNInstructionTextTokenType::PossibleValueToken
893            }
894            InstructionTextTokenKind::PossibleValueType => {
895                BNInstructionTextTokenType::PossibleValueTypeToken
896            }
897            InstructionTextTokenKind::ArrayIndex { .. } => {
898                BNInstructionTextTokenType::ArrayIndexToken
899            }
900            InstructionTextTokenKind::Indentation => BNInstructionTextTokenType::IndentationToken,
901            InstructionTextTokenKind::UnknownMemory => {
902                BNInstructionTextTokenType::UnknownMemoryToken
903            }
904            InstructionTextTokenKind::EnumerationMember { .. } => {
905                BNInstructionTextTokenType::EnumerationMemberToken
906            }
907            InstructionTextTokenKind::Operation => BNInstructionTextTokenType::OperationToken,
908            InstructionTextTokenKind::BaseStructureName => {
909                BNInstructionTextTokenType::BaseStructureNameToken
910            }
911            InstructionTextTokenKind::BaseStructureSeparator => {
912                BNInstructionTextTokenType::BaseStructureSeparatorToken
913            }
914            InstructionTextTokenKind::Brace { .. } => BNInstructionTextTokenType::BraceToken,
915            InstructionTextTokenKind::CodeSymbol { .. } => {
916                BNInstructionTextTokenType::CodeSymbolToken
917            }
918            InstructionTextTokenKind::DataSymbol { .. } => {
919                BNInstructionTextTokenType::DataSymbolToken
920            }
921            InstructionTextTokenKind::LocalVariable { .. } => {
922                BNInstructionTextTokenType::LocalVariableToken
923            }
924            InstructionTextTokenKind::Import { .. } => BNInstructionTextTokenType::ImportToken,
925            InstructionTextTokenKind::AddressDisplay { .. } => {
926                BNInstructionTextTokenType::AddressDisplayToken
927            }
928            InstructionTextTokenKind::IndirectImport { .. } => {
929                BNInstructionTextTokenType::IndirectImportToken
930            }
931            InstructionTextTokenKind::ExternalSymbol { .. } => {
932                BNInstructionTextTokenType::ExternalSymbolToken
933            }
934            InstructionTextTokenKind::StackVariable { .. } => {
935                BNInstructionTextTokenType::StackVariableToken
936            }
937            InstructionTextTokenKind::AddressSeparator => {
938                BNInstructionTextTokenType::AddressSeparatorToken
939            }
940            InstructionTextTokenKind::CollapsedInformation => {
941                BNInstructionTextTokenType::CollapsedInformationToken
942            }
943            InstructionTextTokenKind::CollapseStateIndicator { .. } => {
944                BNInstructionTextTokenType::CollapseStateIndicatorToken
945            }
946            InstructionTextTokenKind::NewLine { .. } => BNInstructionTextTokenType::NewLineToken,
947        }
948    }
949}
950
951impl Eq for InstructionTextTokenKind {}
952
953#[derive(Clone, Copy, PartialEq, Eq, Debug)]
954pub enum InstructionTextTokenContext {
955    Normal,
956    LocalVariable,
957    DataVariable,
958    FunctionReturn,
959    InstructionAddress,
960    ILInstructionIndex,
961    ConstData,
962    /// Use only with [`InstructionTextTokenKind::String`]
963    ConstStringData,
964    /// Use only with [`InstructionTextTokenKind::String`]
965    StringReference,
966    /// Use only with [`InstructionTextTokenKind::String`]
967    StringDataVariable,
968    /// For displaying strings which aren't associated with an address
969    ///
970    /// Use only with [`InstructionTextTokenKind::String`]
971    StringDisplay,
972    /// Use only with [`InstructionTextTokenKind::CollapseStateIndicator`]
973    Collapsed,
974    /// Use only with [`InstructionTextTokenKind::CollapseStateIndicator`]
975    Expanded,
976    /// Use only with [`InstructionTextTokenKind::CollapseStateIndicator`]
977    CollapsiblePadding,
978    /// Use only with [`InstructionTextTokenKind::String`]
979    DerivedStringReference,
980}
981
982impl From<BNInstructionTextTokenContext> for InstructionTextTokenContext {
983    fn from(value: BNInstructionTextTokenContext) -> Self {
984        match value {
985            BNInstructionTextTokenContext::NoTokenContext => Self::Normal,
986            BNInstructionTextTokenContext::LocalVariableTokenContext => Self::LocalVariable,
987            BNInstructionTextTokenContext::DataVariableTokenContext => Self::DataVariable,
988            BNInstructionTextTokenContext::FunctionReturnTokenContext => Self::FunctionReturn,
989            BNInstructionTextTokenContext::InstructionAddressTokenContext => {
990                Self::InstructionAddress
991            }
992            BNInstructionTextTokenContext::ILInstructionIndexTokenContext => {
993                Self::ILInstructionIndex
994            }
995            BNInstructionTextTokenContext::ConstDataTokenContext => Self::ConstData,
996            // For use with [`InstructionTextTokenKind::String`]
997            BNInstructionTextTokenContext::ConstStringDataTokenContext => Self::ConstStringData,
998            BNInstructionTextTokenContext::StringReferenceTokenContext => Self::StringReference,
999            BNInstructionTextTokenContext::StringDataVariableTokenContext => {
1000                Self::StringDataVariable
1001            }
1002            BNInstructionTextTokenContext::StringDisplayTokenContext => Self::StringDisplay,
1003            // For use with [`InstructionTextTokenKind::CollapseStateIndicator`]
1004            BNInstructionTextTokenContext::ContentCollapsedContext => Self::Collapsed,
1005            BNInstructionTextTokenContext::ContentExpandedContext => Self::Expanded,
1006            BNInstructionTextTokenContext::ContentCollapsiblePadding => Self::CollapsiblePadding,
1007            BNInstructionTextTokenContext::DerivedStringReferenceTokenContext => {
1008                Self::DerivedStringReference
1009            }
1010        }
1011    }
1012}
1013
1014impl From<InstructionTextTokenContext> for BNInstructionTextTokenContext {
1015    fn from(value: InstructionTextTokenContext) -> Self {
1016        match value {
1017            InstructionTextTokenContext::Normal => Self::NoTokenContext,
1018            InstructionTextTokenContext::LocalVariable => Self::LocalVariableTokenContext,
1019            InstructionTextTokenContext::DataVariable => Self::DataVariableTokenContext,
1020            InstructionTextTokenContext::FunctionReturn => Self::FunctionReturnTokenContext,
1021            InstructionTextTokenContext::InstructionAddress => Self::InstructionAddressTokenContext,
1022            InstructionTextTokenContext::ILInstructionIndex => Self::ILInstructionIndexTokenContext,
1023            InstructionTextTokenContext::ConstData => Self::ConstDataTokenContext,
1024            InstructionTextTokenContext::ConstStringData => Self::ConstStringDataTokenContext,
1025            InstructionTextTokenContext::StringReference => Self::StringReferenceTokenContext,
1026            InstructionTextTokenContext::StringDataVariable => Self::StringDataVariableTokenContext,
1027            InstructionTextTokenContext::StringDisplay => Self::StringDisplayTokenContext,
1028            InstructionTextTokenContext::Collapsed => Self::ContentCollapsedContext,
1029            InstructionTextTokenContext::Expanded => Self::ContentExpandedContext,
1030            InstructionTextTokenContext::CollapsiblePadding => Self::ContentCollapsiblePadding,
1031            InstructionTextTokenContext::DerivedStringReference => {
1032                Self::DerivedStringReferenceTokenContext
1033            }
1034        }
1035    }
1036}
1037
1038#[repr(transparent)]
1039pub struct DisassemblyTextRenderer {
1040    handle: NonNull<BNDisassemblyTextRenderer>,
1041}
1042
1043impl DisassemblyTextRenderer {
1044    pub unsafe fn ref_from_raw(handle: NonNull<BNDisassemblyTextRenderer>) -> Ref<Self> {
1045        Ref::new(Self { handle })
1046    }
1047
1048    pub fn from_function(func: &Function, settings: Option<&DisassemblySettings>) -> Ref<Self> {
1049        let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
1050        let result = unsafe { BNCreateDisassemblyTextRenderer(func.handle, settings_ptr) };
1051        unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) }
1052    }
1053
1054    pub fn from_llil<M: FunctionMutability, F: FunctionForm>(
1055        func: &LowLevelILFunction<M, F>,
1056        settings: Option<&DisassemblySettings>,
1057    ) -> Ref<Self> {
1058        let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
1059        let result =
1060            unsafe { BNCreateLowLevelILDisassemblyTextRenderer(func.handle, settings_ptr) };
1061        unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) }
1062    }
1063
1064    pub fn from_mlil(
1065        func: &MediumLevelILFunction,
1066        settings: Option<&DisassemblySettings>,
1067    ) -> Ref<Self> {
1068        let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
1069        let result =
1070            unsafe { BNCreateMediumLevelILDisassemblyTextRenderer(func.handle, settings_ptr) };
1071        unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) }
1072    }
1073
1074    pub fn from_hlil(
1075        func: &HighLevelILFunction,
1076        settings: Option<&DisassemblySettings>,
1077    ) -> Ref<Self> {
1078        let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
1079        let result =
1080            unsafe { BNCreateHighLevelILDisassemblyTextRenderer(func.handle, settings_ptr) };
1081        unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) }
1082    }
1083
1084    pub fn function(&self) -> Ref<Function> {
1085        let result = unsafe { BNGetDisassemblyTextRendererFunction(self.handle.as_ptr()) };
1086        assert!(!result.is_null());
1087        unsafe { Function::ref_from_raw(result) }
1088    }
1089
1090    pub fn llil<M: FunctionMutability, F: FunctionForm>(&self) -> Ref<LowLevelILFunction<M, F>> {
1091        let result =
1092            unsafe { BNGetDisassemblyTextRendererLowLevelILFunction(self.handle.as_ptr()) };
1093        assert!(!result.is_null());
1094        unsafe { LowLevelILFunction::ref_from_raw(result) }
1095    }
1096
1097    pub fn mlil(&self) -> Ref<MediumLevelILFunction> {
1098        let result =
1099            unsafe { BNGetDisassemblyTextRendererMediumLevelILFunction(self.handle.as_ptr()) };
1100        assert!(!result.is_null());
1101        unsafe { MediumLevelILFunction::ref_from_raw(result) }
1102    }
1103
1104    pub fn hlil(&self) -> Ref<HighLevelILFunction> {
1105        let result =
1106            unsafe { BNGetDisassemblyTextRendererHighLevelILFunction(self.handle.as_ptr()) };
1107        assert!(!result.is_null());
1108        unsafe { HighLevelILFunction::ref_from_raw(result, true) }
1109    }
1110
1111    pub fn basic_block(&self) -> Option<Ref<BasicBlock<NativeBlock>>> {
1112        let result = unsafe { BNGetDisassemblyTextRendererBasicBlock(self.handle.as_ptr()) };
1113        if result.is_null() {
1114            return None;
1115        }
1116        Some(unsafe { Ref::new(BasicBlock::from_raw(result, NativeBlock::new())) })
1117    }
1118
1119    pub fn set_basic_block(&self, value: Option<&BasicBlock<NativeBlock>>) {
1120        let block_ptr = value.map(|b| b.handle).unwrap_or(ptr::null_mut());
1121        unsafe { BNSetDisassemblyTextRendererBasicBlock(self.handle.as_ptr(), block_ptr) }
1122    }
1123
1124    pub fn arch(&self) -> CoreArchitecture {
1125        let result = unsafe { BNGetDisassemblyTextRendererArchitecture(self.handle.as_ptr()) };
1126        assert!(!result.is_null());
1127        unsafe { CoreArchitecture::from_raw(result) }
1128    }
1129
1130    pub fn set_arch(&self, value: CoreArchitecture) {
1131        unsafe { BNSetDisassemblyTextRendererArchitecture(self.handle.as_ptr(), value.handle) }
1132    }
1133
1134    pub fn settings(&self) -> Ref<DisassemblySettings> {
1135        let result = unsafe { BNGetDisassemblyTextRendererSettings(self.handle.as_ptr()) };
1136        unsafe { DisassemblySettings::ref_from_raw(result) }
1137    }
1138
1139    pub fn set_settings(&self, settings: Option<&DisassemblySettings>) {
1140        let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut());
1141        unsafe { BNSetDisassemblyTextRendererSettings(self.handle.as_ptr(), settings_ptr) }
1142    }
1143
1144    pub fn is_il(&self) -> bool {
1145        unsafe { BNIsILDisassemblyTextRenderer(self.handle.as_ptr()) }
1146    }
1147
1148    pub fn has_data_flow(&self) -> bool {
1149        unsafe { BNDisassemblyTextRendererHasDataFlow(self.handle.as_ptr()) }
1150    }
1151
1152    /// Gets the instructions annotations, like displaying register constant values.
1153    pub fn instruction_annotations(&self, addr: u64) -> Array<InstructionTextToken> {
1154        let mut count = 0;
1155        let result = unsafe {
1156            BNGetDisassemblyTextRendererInstructionAnnotations(
1157                self.handle.as_ptr(),
1158                addr,
1159                &mut count,
1160            )
1161        };
1162        assert!(!result.is_null());
1163        unsafe { Array::new(result, count, ()) }
1164    }
1165
1166    /// Gets the disassembly instruction text only, with no annotations.
1167    pub fn instruction_text(&self, addr: u64) -> Option<(Array<DisassemblyTextLine>, usize)> {
1168        let mut count = 0;
1169        let mut length = 0;
1170        let mut lines: *mut BNDisassemblyTextLine = ptr::null_mut();
1171        let result = unsafe {
1172            BNGetDisassemblyTextRendererInstructionText(
1173                self.handle.as_ptr(),
1174                addr,
1175                &mut length,
1176                &mut lines,
1177                &mut count,
1178            )
1179        };
1180        result.then(|| (unsafe { Array::new(lines, count, ()) }, length))
1181    }
1182
1183    // Gets the disassembly text as it would appear in the UI, with annotations.
1184    pub fn disassembly_text(&self, addr: u64) -> Option<(Array<DisassemblyTextLine>, usize)> {
1185        let mut count = 0;
1186        let mut length = 0;
1187        let mut lines: *mut BNDisassemblyTextLine = ptr::null_mut();
1188        let result = unsafe {
1189            BNGetDisassemblyTextRendererLines(
1190                self.handle.as_ptr(),
1191                addr,
1192                &mut length,
1193                &mut lines,
1194                &mut count,
1195            )
1196        };
1197        result.then(|| (unsafe { Array::new(lines, count, ()) }, length))
1198    }
1199
1200    // TODO post_process_lines BNPostProcessDisassemblyTextRendererLines
1201
1202    pub fn is_integer_token(token_type: InstructionTextTokenType) -> bool {
1203        unsafe { BNIsIntegerToken(token_type) }
1204    }
1205
1206    pub fn reset_deduplicated_comments(&self) {
1207        unsafe { BNResetDisassemblyTextRendererDeduplicatedComments(self.handle.as_ptr()) }
1208    }
1209
1210    pub fn symbol_tokens(
1211        &self,
1212        addr: u64,
1213        size: usize,
1214        operand: Option<usize>,
1215    ) -> Option<Array<InstructionTextToken>> {
1216        let operand = operand.unwrap_or(0xffffffff);
1217        let mut count = 0;
1218        let mut tokens: *mut BNInstructionTextToken = ptr::null_mut();
1219        let result = unsafe {
1220            BNGetDisassemblyTextRendererSymbolTokens(
1221                self.handle.as_ptr(),
1222                addr,
1223                size,
1224                operand,
1225                &mut tokens,
1226                &mut count,
1227            )
1228        };
1229        result.then(|| unsafe { Array::new(tokens, count, ()) })
1230    }
1231
1232    pub fn stack_var_reference_tokens(
1233        &self,
1234        stack_ref: StackVariableReference,
1235    ) -> Array<InstructionTextToken> {
1236        let mut stack_ref_raw = StackVariableReference::into_raw(stack_ref);
1237        let mut count = 0;
1238        let tokens = unsafe {
1239            BNGetDisassemblyTextRendererStackVariableReferenceTokens(
1240                self.handle.as_ptr(),
1241                &mut stack_ref_raw,
1242                &mut count,
1243            )
1244        };
1245        StackVariableReference::free_raw(stack_ref_raw);
1246        assert!(!tokens.is_null());
1247        unsafe { Array::new(tokens, count, ()) }
1248    }
1249
1250    pub fn integer_token(
1251        &self,
1252        int_token: InstructionTextToken,
1253        location: impl Into<Location>,
1254    ) -> Array<InstructionTextToken> {
1255        let location = location.into();
1256        let arch = location
1257            .arch
1258            .map(|a| a.handle)
1259            .unwrap_or_else(std::ptr::null_mut);
1260        let mut count = 0;
1261        let mut int_token_raw = InstructionTextToken::into_raw(int_token);
1262        let tokens = unsafe {
1263            BNGetDisassemblyTextRendererIntegerTokens(
1264                self.handle.as_ptr(),
1265                &mut int_token_raw,
1266                arch,
1267                location.addr,
1268                &mut count,
1269            )
1270        };
1271        InstructionTextToken::free_raw(int_token_raw);
1272        assert!(!tokens.is_null());
1273        unsafe { Array::new(tokens, count, ()) }
1274    }
1275
1276    pub fn wrap_comment(
1277        &self,
1278        cur_line: DisassemblyTextLine,
1279        comment: &str,
1280        has_auto_annotations: bool,
1281        leading_spaces: &str,
1282        indent_spaces: &str,
1283    ) -> Array<DisassemblyTextLine> {
1284        let cur_line_raw = DisassemblyTextLine::into_raw(cur_line);
1285        let comment_raw = comment.to_cstr();
1286        let leading_spaces_raw = leading_spaces.to_cstr();
1287        let indent_spaces_raw = indent_spaces.to_cstr();
1288        let mut count = 0;
1289        let lines = unsafe {
1290            BNDisassemblyTextRendererWrapComment(
1291                self.handle.as_ptr(),
1292                &cur_line_raw,
1293                &mut count,
1294                comment_raw.as_ref().as_ptr() as *const ffi::c_char,
1295                has_auto_annotations,
1296                leading_spaces_raw.as_ref().as_ptr() as *const ffi::c_char,
1297                indent_spaces_raw.as_ref().as_ptr() as *const ffi::c_char,
1298            )
1299        };
1300        DisassemblyTextLine::free_raw(cur_line_raw);
1301        assert!(!lines.is_null());
1302        unsafe { Array::new(lines, count, ()) }
1303    }
1304}
1305
1306impl ToOwned for DisassemblyTextRenderer {
1307    type Owned = Ref<Self>;
1308
1309    fn to_owned(&self) -> Self::Owned {
1310        unsafe { RefCountable::inc_ref(self) }
1311    }
1312}
1313
1314unsafe impl RefCountable for DisassemblyTextRenderer {
1315    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1316        Ref::new(Self {
1317            handle: NonNull::new(BNNewDisassemblyTextRendererReference(
1318                handle.handle.as_ptr(),
1319            ))
1320            .unwrap(),
1321        })
1322    }
1323
1324    unsafe fn dec_ref(handle: &Self) {
1325        BNFreeDisassemblyTextRenderer(handle.handle.as_ptr());
1326    }
1327}
1328
1329// TODO: Make a builder for this.
1330#[derive(PartialEq, Eq, Hash)]
1331pub struct DisassemblySettings {
1332    pub(crate) handle: *mut BNDisassemblySettings,
1333}
1334
1335impl DisassemblySettings {
1336    pub fn ref_from_raw(handle: *mut BNDisassemblySettings) -> Ref<Self> {
1337        debug_assert!(!handle.is_null());
1338        unsafe { Ref::new(Self { handle }) }
1339    }
1340
1341    pub fn new() -> Ref<Self> {
1342        let handle = unsafe { BNCreateDisassemblySettings() };
1343        Self::ref_from_raw(handle)
1344    }
1345
1346    pub fn set_option(&self, option: DisassemblyOption, state: bool) {
1347        unsafe { BNSetDisassemblySettingsOption(self.handle, option, state) }
1348    }
1349
1350    pub fn is_option_set(&self, option: DisassemblyOption) -> bool {
1351        unsafe { BNIsDisassemblySettingsOptionSet(self.handle, option) }
1352    }
1353}
1354
1355impl ToOwned for DisassemblySettings {
1356    type Owned = Ref<Self>;
1357
1358    fn to_owned(&self) -> Self::Owned {
1359        unsafe { RefCountable::inc_ref(self) }
1360    }
1361}
1362
1363unsafe impl RefCountable for DisassemblySettings {
1364    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1365        Ref::new(Self {
1366            handle: BNNewDisassemblySettingsReference(handle.handle),
1367        })
1368    }
1369
1370    unsafe fn dec_ref(handle: &Self) {
1371        BNFreeDisassemblySettings(handle.handle);
1372    }
1373}