binaryninja/
disassembly.rs

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