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