Skip to main content

binaryninja/
architecture.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
15//! Architectures provide disassembly, lifting, and associated metadata about a CPU to inform
16//! analysis and decompilation.
17//!
18//! For more information see the [`Architecture`] trait and the [`CoreArchitecture`] structure for
19//! querying already registered architectures. To override selected behavior of an existing
20//! architecture, implement [`ArchitectureHook`] and call [`register_architecture_hook`].
21
22// RegisterInfo purge
23use binaryninjacore_sys::*;
24use std::fmt::{Debug, Formatter};
25
26use crate::{
27    calling_convention::CoreCallingConvention,
28    data_buffer::DataBuffer,
29    disassembly::InstructionTextToken,
30    ffi::INVALID_REGISTER,
31    function::{Function, Location, NativeBlock},
32    platform::Platform,
33    rc::*,
34    relocation::CoreRelocationHandler,
35    string::{IntoCStr, *},
36    types::{NameAndType, Type},
37    Endianness,
38};
39use std::collections::{HashMap, HashSet};
40use std::ops::Deref;
41use std::{
42    borrow::Borrow,
43    ffi::{c_char, c_void, CString},
44    hash::Hash,
45    mem::MaybeUninit,
46};
47
48use std::ptr::NonNull;
49
50use crate::function_recognizer::FunctionRecognizer;
51use crate::relocation::{CustomRelocationHandlerHandle, RelocationHandler};
52
53use crate::basic_block::BasicBlock;
54use crate::confidence::Conf;
55use crate::logger::Logger;
56use crate::low_level_il::expression::{LowLevelExpressionIndex, ValueExpr};
57use crate::low_level_il::lifting::{
58    get_default_flag_cond_llil, get_default_flag_write_llil, LowLevelILFlagWriteOp,
59};
60use crate::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction};
61
62pub mod basic_block;
63pub mod branches;
64pub mod flag;
65pub mod hook;
66pub mod instruction;
67pub mod intrinsic;
68pub mod register;
69
70// Re-export all the submodules to keep from breaking everyone's code.
71// We split these out just to clarify each part, not necessarily to enforce an extra namespace.
72pub use basic_block::*;
73pub use binaryninjacore_sys::BNLinearSweepAnalysisCapability as LinearSweepAnalysisCapability;
74pub use branches::*;
75pub use flag::*;
76pub use hook::{register_architecture_hook, ArchitectureHook};
77pub use instruction::*;
78pub use intrinsic::*;
79pub use register::*;
80
81/// The [`Architecture`] trait is the backbone of Binary Ninja's analysis capabilities. It tells the
82/// core how to interpret the machine code into LLIL, a generic intermediate representation for
83/// program analysis.
84///
85/// To add support for a new Instruction Set Architecture (ISA), you must implement this trait and
86/// register it. The core analysis loop relies on your implementation for three critical stages:
87///
88/// 1.  **Disassembly ([`Architecture::instruction_text`])**: Machine code into human-readable text (e.g., `55` -> `push rbp`).
89/// 2.  **Control Flow Analysis ([`Architecture::instruction_info`])**: Identifying where execution goes next (e.g., "This is a `call` instruction, it targets address `0x401000`").
90/// 3.  **Lifting ([`Architecture::instruction_llil`])**: Translating machine code into **Low Level Intermediate Language (LLIL)**, which enables decompilation and automated analysis.
91pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
92    type Handle: Borrow<Self> + Clone;
93
94    /// The [`RegisterInfo`] associated with this architecture.
95    type RegisterInfo: RegisterInfo<RegType = Self::Register>;
96
97    /// The [`Register`] associated with this architecture.
98    type Register: Register<InfoType = Self::RegisterInfo>;
99
100    /// The [`RegisterStackInfo`] associated with this architecture.
101    ///
102    /// You may only set this to [`UnusedRegisterStack`] if [`Self::RegisterStack`] is as well.
103    type RegisterStackInfo: RegisterStackInfo<
104        RegType = Self::Register,
105        RegInfoType = Self::RegisterInfo,
106        RegStackType = Self::RegisterStack,
107    >;
108
109    /// The [`RegisterStack`] associated with this architecture.
110    ///
111    /// If you do not override [`Architecture::register_stack_from_id`] and [`Architecture::register_stacks`],
112    /// you may set this to [`UnusedRegisterStack`].
113    type RegisterStack: RegisterStack<
114        InfoType = Self::RegisterStackInfo,
115        RegType = Self::Register,
116        RegInfoType = Self::RegisterInfo,
117    >;
118
119    /// The [`Flag`] associated with this architecture.
120    ///
121    /// If you do not override [`Architecture::flag_from_id`] and [`Architecture::flags`], you may
122    /// set this to [`UnusedFlag`].
123    type Flag: Flag<FlagClass = Self::FlagClass>;
124
125    /// The [`FlagWrite`] associated with this architecture.
126    ///
127    /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that
128    /// this points to a custom [`FlagWrite`] with the following functions defined:
129    ///
130    /// - [`Architecture::flag_write_types`]
131    /// - [`Architecture::flag_write_from_id`]
132    type FlagWrite: FlagWrite<FlagType = Self::Flag, FlagClass = Self::FlagClass>;
133
134    /// The [`FlagClass`] associated with this architecture.
135    ///
136    /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that
137    /// this points to a custom [`FlagClass`] with the following functions defined:
138    ///
139    /// - [`Architecture::flag_classes`]
140    /// - [`Architecture::flag_class_from_id`]
141    type FlagClass: FlagClass;
142
143    /// The [`FlagGroup`] associated with this architecture.
144    ///
145    /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that
146    /// this points to a custom [`FlagGroup`] with the following functions defined:
147    ///
148    /// - [`Architecture::flag_groups`]
149    /// - [`Architecture::flag_group_from_id`]
150    type FlagGroup: FlagGroup<FlagType = Self::Flag, FlagClass = Self::FlagClass>;
151
152    type Intrinsic: Intrinsic;
153
154    fn endianness(&self) -> Endianness;
155    fn address_size(&self) -> usize;
156    fn default_integer_size(&self) -> usize;
157    fn instruction_alignment(&self) -> usize;
158
159    /// Alignment at which an independent linear sweep of an unknown region should begin.
160    fn linear_sweep_initial_alignment(&self) -> usize {
161        self.instruction_alignment()
162    }
163
164    /// Generic linear sweep algorithms that are valid for this architecture.
165    fn linear_sweep_analysis_capabilities(&self) -> u32 {
166        LinearSweepAnalysisCapability::BNLinearSweepCallTargetAnalysis as u32
167            | LinearSweepAnalysisCapability::BNLinearSweepGenericControlFlowAnalysis as u32
168    }
169
170    /// Whether instruction decoding, disassembly, and lifting are valid without function-level
171    /// context.
172    fn supports_standalone_instruction_decoding(&self) -> bool {
173        true
174    }
175
176    /// The maximum length of an instruction in bytes. This is used to determine the size of the buffer
177    /// given to callbacks such as [`Architecture::instruction_info`], [`Architecture::instruction_text`]
178    /// and [`Architecture::instruction_llil`].
179    ///
180    /// NOTE: The maximum **CANNOT** be greater than 256.
181    fn max_instr_len(&self) -> usize;
182
183    /// How many bytes to display in the opcode space before displaying a `...`, typically set to
184    /// the [`Architecture::max_instr_len`], however, can be overridden to display a truncated opcode.
185    fn opcode_display_len(&self) -> usize {
186        self.max_instr_len()
187    }
188
189    /// In binaries with multiple architectures, you may wish to associate a specific architecture
190    /// with a given virtual address. This can be seen in armv7 where odd addresses are associated
191    /// with the thumb architecture.
192    ///
193    /// The address can be updated in place to normalize it, such as clearing the ARM Thumb bit.
194    fn associated_arch_by_addr(&self, _addr: &mut u64) -> CoreArchitecture {
195        *self.as_ref()
196    }
197
198    /// Returns the [`InstructionInfo`] at the given virtual address with `data`.
199    ///
200    /// The [`InstructionInfo`] object should always fill the proper length and branches if not, the
201    /// next instruction will likely be incorrect.
202    fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo>;
203
204    /// Disassembles a raw byte sequence into a human-readable list of text tokens.
205    ///
206    /// This function is responsible for the visual representation of assembly instructions.
207    /// It does *not* define semantics (use [`Architecture::instruction_llil`] for that);
208    /// it simply tells the UI how to print the instruction.
209    ///
210    /// # Returns
211    ///
212    /// An `Option` containing a tuple:
213    ///
214    /// * `usize`: The size of the decoded instruction in bytes. Is used to advance to the next instruction.
215    /// * `Vec<InstructionTextToken>`: A list of text tokens representing the instruction.
216    ///
217    /// Returns `None` if the bytes do not form a valid instruction.
218    fn instruction_text(
219        &self,
220        data: &[u8],
221        addr: u64,
222    ) -> Option<(usize, Vec<InstructionTextToken>)>;
223
224    /// Disassembles a raw byte sequence into a human-readable list of text tokens.
225    ///
226    /// This function is responsible for the visual representation of assembly instructions.
227    /// It does *not* define semantics (use [`Architecture::instruction_llil`] for that);
228    /// it simply tells the UI how to print the instruction. This variant includes contextual data, which
229    /// can be produced by analyze_basic_blocks
230    ///
231    /// # Returns
232    ///
233    /// An `Option` containing a tuple:
234    ///
235    /// * `usize`: The size of the decoded instruction in bytes. Is used to advance to the next instruction.
236    /// * `Vec<InstructionTextToken>`: A list of text tokens representing the instruction.
237    ///
238    /// Returns `None` if the bytes do not form a valid instruction.
239    fn instruction_text_with_context(
240        &self,
241        data: &[u8],
242        addr: u64,
243        _context: Option<NonNull<c_void>>,
244    ) -> Option<(usize, Vec<InstructionTextToken>)> {
245        self.instruction_text(data, addr)
246    }
247
248    /// Appends arbitrary low-level il instructions to `il`.
249    ///
250    /// Returns the decoded length and whether lifting succeeded. `Some((length, false))` preserves
251    /// the decoded length even when lifting fails. `None` reports failure without updating the
252    /// caller's length.
253    fn instruction_llil(
254        &self,
255        data: &[u8],
256        addr: u64,
257        il: &LowLevelILMutableFunction,
258    ) -> Option<(usize, bool)>;
259
260    /// Performs basic block recovery and commits the results to the function analysis.
261    ///
262    /// NOTE: Only implement this method if function-level analysis is required. Otherwise, do not
263    /// implement to let default basic block analysis take place.
264    fn analyze_basic_blocks(
265        &self,
266        function: &mut Function,
267        context: &mut BasicBlockAnalysisContext,
268    ) {
269        unsafe {
270            BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context.handle);
271        }
272    }
273
274    fn lift_function(
275        &self,
276        function: LowLevelILMutableFunction,
277        context: &mut FunctionLifterContext,
278    ) -> bool {
279        unsafe { BNArchitectureDefaultLiftFunction(function.handle, context.handle) }
280    }
281
282    /// Fallback flag value calculation path. This method is invoked when the core is unable to
283    /// recover the flag using semantics and resorts to emitting instructions that explicitly set each
284    /// observed flag to the value of an expression returned by this function.
285    ///
286    /// This function *MUST NOT* append instructions that have side effects.
287    ///
288    /// This function *MUST NOT* observe the values of other flags.
289    ///
290    /// This function *MUST* return `None` or an expression representing a boolean value.
291    fn flag_write_llil<'a>(
292        &self,
293        flag: Self::Flag,
294        flag_write_type: Self::FlagWrite,
295        op: LowLevelILFlagWriteOp<Self::Register>,
296        il: &'a LowLevelILMutableFunction,
297    ) -> Option<LowLevelILMutableExpression<'a, ValueExpr>> {
298        let role = flag.role(flag_write_type.class());
299        Some(get_default_flag_write_llil(self, role, op, il))
300    }
301
302    /// Determines what flags need to be examined to attempt automatic recovery of the flag uses semantics.
303    ///
304    /// If automatic recovery is not possible, the [`Architecture::flag_cond_llil`] method will be invoked
305    /// to give this [`Architecture`] implementation arbitrary control over the expression to be evaluated.
306    fn flags_required_for_flag_condition(
307        &self,
308        _condition: FlagCondition,
309        _class: Option<Self::FlagClass>,
310    ) -> Vec<Self::Flag> {
311        Vec::new()
312    }
313
314    /// This function *MUST NOT* append instructions that have side effects.
315    ///
316    /// This function *MUST NOT* observe the values of flags not returned by
317    /// `flags_required_for_flag_condition`.
318    ///
319    /// This function *MUST* return `None` or an expression representing a boolean value.
320    fn flag_cond_llil<'a>(
321        &self,
322        cond: FlagCondition,
323        class: Option<Self::FlagClass>,
324        il: &'a LowLevelILMutableFunction,
325    ) -> Option<LowLevelILMutableExpression<'a, ValueExpr>> {
326        Some(get_default_flag_cond_llil(self, cond, class, il))
327    }
328
329    /// Performs fallback resolution when the core was unable to recover the semantics of a
330    /// `LLIL_FLAG_GROUP` expression. This occurs when multiple instructions may have set the flags
331    /// at the flag group query, or when the `FlagGroup::flag_conditions()` map doesn't have an entry
332    /// for the `FlagClass` associated with the `FlagWrite` type of the expression that last set
333    /// the flags required by the `FlagGroup` `group`.
334    ///
335    /// In this fallback path, the `Architecture` must generate the boolean expression in terms of
336    /// the values of that flags returned by `group`'s `flags_required` method.
337    ///
338    /// This function must return an expression representing a boolean (as in, size of `0`) value.
339    /// It is not allowed to add any instructions that can cause side effects.
340    ///
341    /// This function must not observe the values of any flag not returned by `group`'s
342    /// `flags_required` method.
343    fn flag_group_llil<'a>(
344        &self,
345        _group: Self::FlagGroup,
346        _il: &'a LowLevelILMutableFunction,
347    ) -> Option<LowLevelILMutableExpression<'a, ValueExpr>> {
348        None
349    }
350
351    fn registers_all(&self) -> Vec<Self::Register>;
352
353    fn register_from_id(&self, id: RegisterId) -> Option<Self::Register>;
354
355    fn registers_full_width(&self) -> Vec<Self::Register>;
356
357    // TODO: Document the difference between global and system registers.
358    fn registers_global(&self) -> Vec<Self::Register> {
359        Vec::new()
360    }
361
362    // TODO: Document the difference between global and system registers.
363    fn registers_system(&self) -> Vec<Self::Register> {
364        Vec::new()
365    }
366
367    fn stack_pointer_reg(&self) -> Option<Self::Register>;
368
369    fn link_reg(&self) -> Option<Self::Register> {
370        None
371    }
372
373    /// List of concrete register stacks for this architecture.
374    ///
375    /// You **must** override the following functions as well:
376    ///
377    /// - [`Architecture::register_stack_from_id`]
378    fn register_stacks(&self) -> Vec<Self::RegisterStack> {
379        Vec::new()
380    }
381
382    /// Get the [`Self::RegisterStack`] associated with the given [`RegisterStackId`].
383    ///
384    /// You **must** override the following functions as well:
385    ///
386    /// - [`Architecture::register_stacks`]
387    fn register_stack_from_id(&self, _id: RegisterStackId) -> Option<Self::RegisterStack> {
388        None
389    }
390
391    /// List of concrete flags for this architecture.
392    ///
393    /// You **must** override the following functions as well:
394    ///
395    /// - [`Architecture::flag_from_id`]
396    /// - [`Architecture::flag_write_types`]
397    /// - [`Architecture::flag_write_from_id`]
398    /// - [`Architecture::flag_classes`]
399    /// - [`Architecture::flag_class_from_id`]
400    /// - [`Architecture::flag_groups`]
401    /// - [`Architecture::flag_group_from_id`]
402    fn flags(&self) -> Vec<Self::Flag> {
403        Vec::new()
404    }
405
406    /// Get the [`Self::Flag`] associated with the given [`FlagId`].
407    ///
408    /// You **must** override the following functions as well:
409    ///
410    /// - [`Architecture::flags`]
411    /// - [`Architecture::flag_write_types`]
412    /// - [`Architecture::flag_write_from_id`]
413    /// - [`Architecture::flag_classes`]
414    /// - [`Architecture::flag_class_from_id`]
415    /// - [`Architecture::flag_groups`]
416    /// - [`Architecture::flag_group_from_id`]
417    fn flag_from_id(&self, _id: FlagId) -> Option<Self::Flag> {
418        None
419    }
420
421    /// List of concrete flag write types for this architecture.
422    ///
423    /// You **must** override the following functions as well:
424    ///
425    /// - [`Architecture::flags`]
426    /// - [`Architecture::flag_from_id`]
427    /// - [`Architecture::flag_write_from_id`]
428    /// - [`Architecture::flag_classes`]
429    /// - [`Architecture::flag_class_from_id`]
430    /// - [`Architecture::flag_groups`]
431    /// - [`Architecture::flag_group_from_id`]
432    fn flag_write_types(&self) -> Vec<Self::FlagWrite> {
433        Vec::new()
434    }
435
436    /// Get the [`Self::FlagWrite`] associated with the given [`FlagWriteId`].
437    ///
438    /// You **must** override the following functions as well:
439    ///
440    /// - [`Architecture::flags`]
441    /// - [`Architecture::flag_from_id`]
442    /// - [`Architecture::flag_write_types`]
443    /// - [`Architecture::flag_classes`]
444    /// - [`Architecture::flag_class_from_id`]
445    /// - [`Architecture::flag_groups`]
446    /// - [`Architecture::flag_group_from_id`]
447    fn flag_write_from_id(&self, _id: FlagWriteId) -> Option<Self::FlagWrite> {
448        None
449    }
450
451    /// List of concrete flag classes for this architecture.
452    ///
453    /// You **must** override the following functions as well:
454    ///
455    /// - [`Architecture::flags`]
456    /// - [`Architecture::flag_from_id`]
457    /// - [`Architecture::flag_write_from_id`]
458    /// - [`Architecture::flag_class_from_id`]
459    /// - [`Architecture::flag_groups`]
460    /// - [`Architecture::flag_group_from_id`]
461    fn flag_classes(&self) -> Vec<Self::FlagClass> {
462        Vec::new()
463    }
464
465    /// Get the [`Self::FlagClass`] associated with the given [`FlagClassId`].
466    ///
467    /// You **must** override the following functions as well:
468    ///
469    /// - [`Architecture::flags`]
470    /// - [`Architecture::flag_from_id`]
471    /// - [`Architecture::flag_write_from_id`]
472    /// - [`Architecture::flag_classes`]
473    /// - [`Architecture::flag_groups`]
474    /// - [`Architecture::flag_group_from_id`]
475    fn flag_class_from_id(&self, _id: FlagClassId) -> Option<Self::FlagClass> {
476        None
477    }
478
479    /// List of concrete flag groups for this architecture.
480    ///
481    /// You **must** override the following functions as well:
482    ///
483    /// - [`Architecture::flags`]
484    /// - [`Architecture::flag_from_id`]
485    /// - [`Architecture::flag_write_from_id`]
486    /// - [`Architecture::flag_classes`]
487    /// - [`Architecture::flag_class_from_id`]
488    /// - [`Architecture::flag_group_from_id`]
489    fn flag_groups(&self) -> Vec<Self::FlagGroup> {
490        Vec::new()
491    }
492
493    /// Get the [`Self::FlagGroup`] associated with the given [`FlagGroupId`].
494    ///
495    /// You **must** override the following functions as well:
496    ///
497    /// - [`Architecture::flags`]
498    /// - [`Architecture::flag_from_id`]
499    /// - [`Architecture::flag_write_from_id`]
500    /// - [`Architecture::flag_classes`]
501    /// - [`Architecture::flag_class_from_id`]
502    /// - [`Architecture::flag_groups`]
503    fn flag_group_from_id(&self, _id: FlagGroupId) -> Option<Self::FlagGroup> {
504        None
505    }
506
507    /// List of concrete intrinsics for this architecture.
508    ///
509    /// You **must** override the following functions as well:
510    ///
511    /// - [`Architecture::intrinsic_from_id`]
512    fn intrinsics(&self) -> Vec<Self::Intrinsic> {
513        Vec::new()
514    }
515
516    /// Returns the class from [`Intrinsic::class`], or the general class for an unknown ID.
517    fn intrinsic_class(&self, id: IntrinsicId) -> BNIntrinsicClass {
518        match self.intrinsic_from_id(id) {
519            Some(intrinsic) => intrinsic.class(),
520            None => BNIntrinsicClass::GeneralIntrinsicClass,
521        }
522    }
523
524    /// Get the [`Self::Intrinsic`] associated with the given [`IntrinsicId`].
525    ///
526    /// You **must** override the following functions as well:
527    ///
528    /// - [`Architecture::intrinsics`]
529    fn intrinsic_from_id(&self, _id: IntrinsicId) -> Option<Self::Intrinsic> {
530        None
531    }
532
533    /// Let the UI display this patch option.
534    ///
535    /// If set to true, you must override [`Architecture::assemble`].
536    fn can_assemble(&self) -> bool {
537        false
538    }
539
540    /// Assemble the code at the specified address and return the machine code in bytes.
541    ///
542    /// If overridden, you must set [`Architecture::can_assemble`] to `true`.
543    fn assemble(&self, _code: &str, _addr: u64) -> Result<Vec<u8>, String> {
544        Err("Assemble unsupported".into())
545    }
546
547    /// Let the UI display this patch option.
548    ///
549    /// If set to true, you must override [`Architecture::invert_branch`].
550    fn is_never_branch_patch_available(&self, data: &[u8], addr: u64) -> bool {
551        self.is_invert_branch_patch_available(data, addr)
552    }
553
554    /// Let the UI display this patch option.
555    ///
556    /// If set to true, you must override [`Architecture::always_branch`].
557    fn is_always_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
558        false
559    }
560
561    /// Let the UI display this patch option.
562    ///
563    /// If set to true, you must override [`Architecture::invert_branch`].
564    fn is_invert_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
565        false
566    }
567
568    /// Let the UI display this patch option.
569    ///
570    /// If set to true, you must override [`Architecture::skip_and_return_value`].
571    fn is_skip_and_return_zero_patch_available(&self, data: &[u8], addr: u64) -> bool {
572        self.is_skip_and_return_value_patch_available(data, addr)
573    }
574
575    /// Let the UI display this patch option.
576    ///
577    /// If set to true, you must override [`Architecture::skip_and_return_value`].
578    fn is_skip_and_return_value_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
579        false
580    }
581
582    fn convert_to_nop(&self, _data: &mut [u8], _addr: u64) -> bool {
583        false
584    }
585
586    /// Patch the instruction to always branch.
587    ///
588    /// If overridden, you must also override [`Architecture::is_always_branch_patch_available`].
589    fn always_branch(&self, _data: &mut [u8], _addr: u64) -> bool {
590        false
591    }
592
593    /// Patch the instruction to invert the branch condition.
594    ///
595    /// If overridden, you must also override [`Architecture::is_invert_branch_patch_available`].
596    fn invert_branch(&self, _data: &mut [u8], _addr: u64) -> bool {
597        false
598    }
599
600    /// Patch the instruction to skip and return value.
601    ///
602    /// If overridden, you must also override [`Architecture::is_skip_and_return_value_patch_available`].
603    fn skip_and_return_value(&self, _data: &mut [u8], _addr: u64, _value: u64) -> bool {
604        false
605    }
606
607    fn handle(&self) -> Self::Handle;
608}
609
610pub trait ArchitectureWithFunctionContext: Architecture {
611    type FunctionArchContext: Send + Sync + 'static;
612
613    fn instruction_text_with_typed_context(
614        &self,
615        data: &[u8],
616        addr: u64,
617        _context: Option<&Self::FunctionArchContext>,
618    ) -> Option<(usize, Vec<InstructionTextToken>)> {
619        self.instruction_text(data, addr)
620    }
621}
622
623pub struct FunctionLifterContext {
624    pub(crate) handle: *mut BNFunctionLifterContext,
625    pub function: Ref<LowLevelILMutableFunction>,
626    pub platform: Ref<Platform>,
627    pub logger: Ref<Logger>,
628    pub blocks: Vec<Ref<BasicBlock<NativeBlock>>>,
629    pub no_return_calls: HashSet<Location>,
630    pub contextual_returns: HashMap<Location, bool>,
631    pub inlined_remapping: HashMap<Location, Location>,
632    pub user_indirect_branches: HashMap<Location, HashSet<Location>>,
633    pub auto_indirect_branches: HashMap<Location, HashSet<Location>>,
634    pub inlined_calls: HashSet<u64>,
635}
636
637unsafe fn lifter_context_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
638    if len == 0 {
639        &[]
640    } else {
641        debug_assert!(!ptr.is_null());
642        unsafe { std::slice::from_raw_parts(ptr, len) }
643    }
644}
645
646impl FunctionLifterContext {
647    pub unsafe fn from_raw(
648        function: *mut BNLowLevelILFunction,
649        handle: *mut BNFunctionLifterContext,
650    ) -> Self {
651        Self::from_raw_with_arch(function, handle, None)
652    }
653
654    pub(crate) unsafe fn from_raw_with_arch(
655        function: *mut BNLowLevelILFunction,
656        handle: *mut BNFunctionLifterContext,
657        arch: Option<CoreArchitecture>,
658    ) -> Self {
659        debug_assert!(!function.is_null());
660        debug_assert!(!handle.is_null());
661        let flc_ref = &*handle;
662        let platform = unsafe { Platform::ref_from_raw(BNNewPlatformReference(flc_ref.platform)) };
663        let logger = unsafe { Logger::ref_from_raw(BNNewLoggerReference(flc_ref.logger)) };
664
665        let mut blocks = Vec::new();
666        for i in 0..flc_ref.basicBlockCount {
667            let block = unsafe {
668                Some(BasicBlock::ref_from_raw(
669                    BNNewBasicBlockReference(*flc_ref.basicBlocks.add(i)),
670                    NativeBlock::new(),
671                ))
672            };
673
674            blocks.push(block.unwrap());
675        }
676
677        let raw_no_return_calls: &[BNArchitectureAndAddress] =
678            lifter_context_slice(flc_ref.noReturnCalls, flc_ref.noReturnCallsCount);
679        let no_return_calls: HashSet<Location> =
680            raw_no_return_calls.iter().map(Location::from).collect();
681
682        let raw_contextual_return_locs: &[BNArchitectureAndAddress] = unsafe {
683            lifter_context_slice(
684                flc_ref.contextualFunctionReturnLocations,
685                flc_ref.contextualFunctionReturnCount,
686            )
687        };
688        let raw_contextual_return_vals: &[bool] = unsafe {
689            lifter_context_slice(
690                flc_ref.contextualFunctionReturnValues,
691                flc_ref.contextualFunctionReturnCount,
692            )
693        };
694        let contextual_returns: HashMap<Location, bool> = raw_contextual_return_locs
695            .iter()
696            .map(Location::from)
697            .zip(raw_contextual_return_vals.iter().copied())
698            .collect();
699
700        let inlined_remapping: HashMap<Location, Location> = {
701            let raw_inline_remap_locs: &[BNArchitectureAndAddress] = lifter_context_slice(
702                flc_ref.inlinedRemappingKeys,
703                flc_ref.inlinedRemappingEntryCount,
704            );
705
706            let raw_inline_remap_dests: &[BNArchitectureAndAddress] = lifter_context_slice(
707                flc_ref.inlinedRemappingValues,
708                flc_ref.inlinedRemappingEntryCount,
709            );
710
711            raw_inline_remap_locs
712                .iter()
713                .map(Location::from)
714                .zip(raw_inline_remap_dests.iter().map(Location::from))
715                .collect()
716        };
717
718        let mut user_indirect_branches: HashMap<Location, HashSet<Location>> = HashMap::new();
719        let mut auto_indirect_branches: HashMap<Location, HashSet<Location>> = HashMap::new();
720        for i in 0..flc_ref.indirectBranchesCount {
721            let entry = unsafe { *flc_ref.indirectBranches.add(i) };
722            let src = Location::new(
723                Some(CoreArchitecture::from_raw(entry.sourceArch)),
724                entry.sourceAddr,
725            );
726            let dest = Location::new(
727                Some(CoreArchitecture::from_raw(entry.destArch)),
728                entry.destAddr,
729            );
730            if entry.autoDefined {
731                auto_indirect_branches.entry(src).or_default().insert(dest);
732            } else {
733                user_indirect_branches.entry(src).or_default().insert(dest);
734            }
735        }
736
737        let inlined_calls: HashSet<u64> =
738            lifter_context_slice(flc_ref.inlinedCalls, flc_ref.inlinedCallsCount)
739                .iter()
740                .copied()
741                .collect();
742
743        FunctionLifterContext {
744            handle,
745            function: LowLevelILMutableFunction::ref_from_raw_with_arch(
746                BNNewLowLevelILFunctionReference(function),
747                arch,
748            ),
749            platform,
750            logger,
751            blocks,
752            no_return_calls,
753            contextual_returns,
754            inlined_remapping,
755            user_indirect_branches,
756            auto_indirect_branches,
757            inlined_calls,
758        }
759    }
760
761    pub fn prepare_block_translation(
762        &self,
763        func: &LowLevelILMutableFunction,
764        arch: &CoreArchitecture,
765        address: u64,
766    ) {
767        unsafe {
768            BNPrepareBlockTranslation(func.handle, arch.handle, address);
769        }
770    }
771
772    /// The per-function instruction byte store populated during basic block analysis. Read it here
773    /// to avoid reading the view during lifting.
774    pub fn lifter_instruction_data(&self) -> Option<LifterInstructionData> {
775        let handle = unsafe { (*self.handle).lifterInstructionData };
776        if handle.is_null() {
777            None
778        } else {
779            Some(unsafe { LifterInstructionData::from_raw(handle) })
780        }
781    }
782
783    pub fn get_function_arch_context<A: ArchitectureWithFunctionContext>(
784        &self,
785        _arch: &A,
786    ) -> Option<&A::FunctionArchContext> {
787        unsafe {
788            let ptr = (*self.handle).functionArchContext;
789            if ptr.is_null() {
790                None
791            } else {
792                Some(&*(ptr as *const A::FunctionArchContext))
793            }
794        }
795    }
796}
797
798// TODO: WTF?!?!?!?
799pub struct CoreArchitectureList(*mut *mut BNArchitecture, usize);
800
801impl Deref for CoreArchitectureList {
802    type Target = [CoreArchitecture];
803
804    fn deref(&self) -> &Self::Target {
805        unsafe { std::slice::from_raw_parts_mut(self.0 as *mut CoreArchitecture, self.1) }
806    }
807}
808
809impl Drop for CoreArchitectureList {
810    fn drop(&mut self) {
811        unsafe {
812            BNFreeArchitectureList(self.0);
813        }
814    }
815}
816
817#[derive(Copy, Clone, Eq, PartialEq, Hash)]
818pub struct CoreArchitecture {
819    pub(crate) handle: *mut BNArchitecture,
820}
821
822impl CoreArchitecture {
823    // TODO: Leave a note on architecture lifetimes. Specifically that they are never freed.
824    pub unsafe fn from_raw(handle: *mut BNArchitecture) -> Self {
825        debug_assert!(!handle.is_null());
826        CoreArchitecture { handle }
827    }
828
829    pub fn list_all() -> CoreArchitectureList {
830        let mut count: usize = 0;
831        let archs = unsafe { BNGetArchitectureList(&mut count) };
832
833        CoreArchitectureList(archs, count)
834    }
835
836    pub fn by_name(name: &str) -> Option<Self> {
837        let name = name.to_cstr();
838        let handle = unsafe { BNGetArchitectureByName(name.as_ptr()) };
839        match handle.is_null() {
840            false => Some(CoreArchitecture { handle }),
841            true => None,
842        }
843    }
844
845    pub fn name(&self) -> String {
846        unsafe { BnString::into_string(BNGetArchitectureName(self.handle)) }
847    }
848
849    pub fn register_stack_for_register(&self, reg: CoreRegister) -> Option<CoreRegisterStack> {
850        match unsafe { BNGetArchitectureRegisterStackForRegister(self.handle, reg.id().0) } {
851            INVALID_REGISTER => None,
852            reg_stack => CoreRegisterStack::new(*self, RegisterStackId::from(reg_stack)),
853        }
854    }
855}
856
857unsafe impl Send for CoreArchitecture {}
858unsafe impl Sync for CoreArchitecture {}
859
860impl AsRef<CoreArchitecture> for CoreArchitecture {
861    fn as_ref(&self) -> &Self {
862        self
863    }
864}
865
866impl Architecture for CoreArchitecture {
867    type Handle = Self;
868
869    type RegisterInfo = CoreRegisterInfo;
870    type Register = CoreRegister;
871    type RegisterStackInfo = CoreRegisterStackInfo;
872    type RegisterStack = CoreRegisterStack;
873    type Flag = CoreFlag;
874    type FlagWrite = CoreFlagWrite;
875    type FlagClass = CoreFlagClass;
876    type FlagGroup = CoreFlagGroup;
877    type Intrinsic = CoreIntrinsic;
878
879    fn endianness(&self) -> Endianness {
880        unsafe { BNGetArchitectureEndianness(self.handle) }
881    }
882
883    fn address_size(&self) -> usize {
884        unsafe { BNGetArchitectureAddressSize(self.handle) }
885    }
886
887    fn default_integer_size(&self) -> usize {
888        unsafe { BNGetArchitectureDefaultIntegerSize(self.handle) }
889    }
890
891    fn instruction_alignment(&self) -> usize {
892        unsafe { BNGetArchitectureInstructionAlignment(self.handle) }
893    }
894
895    fn linear_sweep_initial_alignment(&self) -> usize {
896        unsafe { BNGetArchitectureLinearSweepInitialAlignment(self.handle) }
897    }
898
899    fn linear_sweep_analysis_capabilities(&self) -> u32 {
900        unsafe { BNGetArchitectureLinearSweepAnalysisCapabilities(self.handle) }
901    }
902
903    fn supports_standalone_instruction_decoding(&self) -> bool {
904        unsafe { BNArchitectureSupportsStandaloneInstructionDecoding(self.handle) }
905    }
906
907    fn max_instr_len(&self) -> usize {
908        unsafe { BNGetArchitectureMaxInstructionLength(self.handle) }
909    }
910
911    fn opcode_display_len(&self) -> usize {
912        unsafe { BNGetArchitectureOpcodeDisplayLength(self.handle) }
913    }
914
915    fn associated_arch_by_addr(&self, addr: &mut u64) -> CoreArchitecture {
916        let handle = unsafe { BNGetAssociatedArchitectureByAddress(self.handle, addr) };
917        CoreArchitecture { handle }
918    }
919
920    fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo> {
921        let mut info = BNInstructionInfo::default();
922        if unsafe { BNGetInstructionInfo(self.handle, data.as_ptr(), addr, data.len(), &mut info) }
923        {
924            Some(info.into())
925        } else {
926            None
927        }
928    }
929
930    fn instruction_text(
931        &self,
932        data: &[u8],
933        addr: u64,
934    ) -> Option<(usize, Vec<InstructionTextToken>)> {
935        let mut consumed = data.len();
936        let mut count: usize = 0;
937        let mut result: *mut BNInstructionTextToken = std::ptr::null_mut();
938
939        unsafe {
940            if BNGetInstructionText(
941                self.handle,
942                data.as_ptr(),
943                addr,
944                &mut consumed,
945                &mut result,
946                &mut count,
947            ) {
948                let instr_text_tokens = std::slice::from_raw_parts(result, count)
949                    .iter()
950                    .map(InstructionTextToken::from_raw)
951                    .collect();
952                BNFreeInstructionText(result, count);
953                Some((consumed, instr_text_tokens))
954            } else {
955                None
956            }
957        }
958    }
959
960    fn instruction_text_with_context(
961        &self,
962        data: &[u8],
963        addr: u64,
964        context: Option<NonNull<c_void>>,
965    ) -> Option<(usize, Vec<InstructionTextToken>)> {
966        let mut consumed = data.len();
967        let mut count: usize = 0;
968        let mut result: *mut BNInstructionTextToken = std::ptr::null_mut();
969        let ctx_ptr: *mut c_void = context.map_or(std::ptr::null_mut(), |p| p.as_ptr());
970        unsafe {
971            if BNGetInstructionTextWithContext(
972                self.handle,
973                data.as_ptr(),
974                addr,
975                &mut consumed,
976                ctx_ptr,
977                &mut result,
978                &mut count,
979            ) {
980                let instr_text_tokens = std::slice::from_raw_parts(result, count)
981                    .iter()
982                    .map(InstructionTextToken::from_raw)
983                    .collect();
984                BNFreeInstructionText(result, count);
985                Some((consumed, instr_text_tokens))
986            } else {
987                None
988            }
989        }
990    }
991
992    fn instruction_llil(
993        &self,
994        data: &[u8],
995        addr: u64,
996        il: &LowLevelILMutableFunction,
997    ) -> Option<(usize, bool)> {
998        let mut size = data.len();
999        let success = unsafe {
1000            BNGetInstructionLowLevelIL(
1001                self.handle,
1002                data.as_ptr(),
1003                addr,
1004                &mut size as *mut _,
1005                il.handle,
1006            )
1007        };
1008
1009        Some((size, success))
1010    }
1011
1012    /// Performs basic block recovery and commits the results to the function analysis.
1013    ///
1014    /// NOTE: Only implement this method if function-level analysis is required. Otherwise, do not
1015    /// implement to let default basic block analysis take place.
1016    ///
1017    /// NOTE: The default implementation exists in C++ here: <https://github.com/Vector35/binaryninja-api/blob/dev/defaultabb.cpp>
1018    fn analyze_basic_blocks(
1019        &self,
1020        function: &mut Function,
1021        context: &mut BasicBlockAnalysisContext,
1022    ) {
1023        unsafe {
1024            BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context.handle);
1025        }
1026    }
1027
1028    fn lift_function(
1029        &self,
1030        function: LowLevelILMutableFunction,
1031        context: &mut FunctionLifterContext,
1032    ) -> bool {
1033        unsafe { BNArchitectureLiftFunction(self.handle, function.handle, context.handle) }
1034    }
1035
1036    fn flag_write_llil<'a>(
1037        &self,
1038        flag: Self::Flag,
1039        flag_write: Self::FlagWrite,
1040        op: LowLevelILFlagWriteOp<Self::Register>,
1041        il: &'a LowLevelILMutableFunction,
1042    ) -> Option<LowLevelILMutableExpression<'a, ValueExpr>> {
1043        let (size, operation) = op.size_and_op();
1044        let mut operands = op.raw_operands();
1045        let index = unsafe {
1046            BNGetArchitectureFlagWriteLowLevelIL(
1047                self.handle,
1048                operation,
1049                size,
1050                flag_write.id().0,
1051                flag.id().0,
1052                operands.as_mut_ptr(),
1053                operands.len(),
1054                il.handle,
1055            )
1056        };
1057        Some(LowLevelILMutableExpression::new(
1058            il,
1059            LowLevelExpressionIndex(index),
1060        ))
1061    }
1062
1063    fn flags_required_for_flag_condition(
1064        &self,
1065        condition: FlagCondition,
1066        class: Option<Self::FlagClass>,
1067    ) -> Vec<Self::Flag> {
1068        let class_id_raw = class.map(|c| c.id().0).unwrap_or(0);
1069
1070        unsafe {
1071            let mut count: usize = 0;
1072            let flags = BNGetArchitectureFlagsRequiredForFlagCondition(
1073                self.handle,
1074                condition,
1075                class_id_raw,
1076                &mut count,
1077            );
1078
1079            let ret = std::slice::from_raw_parts(flags, count)
1080                .iter()
1081                .map(|&id| FlagId::from(id))
1082                .filter_map(|flag| CoreFlag::new(*self, flag))
1083                .collect();
1084
1085            BNFreeRegisterList(flags);
1086
1087            ret
1088        }
1089    }
1090
1091    fn flag_cond_llil<'a>(
1092        &self,
1093        cond: FlagCondition,
1094        class: Option<Self::FlagClass>,
1095        il: &'a LowLevelILMutableFunction,
1096    ) -> Option<LowLevelILMutableExpression<'a, ValueExpr>> {
1097        let index = unsafe {
1098            BNGetArchitectureFlagConditionLowLevelIL(
1099                self.handle,
1100                cond,
1101                class.map_or(0, |class| class.id().0),
1102                il.handle,
1103            )
1104        };
1105        Some(LowLevelILMutableExpression::new(
1106            il,
1107            LowLevelExpressionIndex(index),
1108        ))
1109    }
1110
1111    fn flag_group_llil<'a>(
1112        &self,
1113        group: Self::FlagGroup,
1114        il: &'a LowLevelILMutableFunction,
1115    ) -> Option<LowLevelILMutableExpression<'a, ValueExpr>> {
1116        let index = unsafe {
1117            BNGetArchitectureSemanticFlagGroupLowLevelIL(self.handle, group.id().0, il.handle)
1118        };
1119        Some(LowLevelILMutableExpression::new(
1120            il,
1121            LowLevelExpressionIndex(index),
1122        ))
1123    }
1124
1125    fn registers_all(&self) -> Vec<CoreRegister> {
1126        unsafe {
1127            let mut count: usize = 0;
1128            let registers_raw = BNGetAllArchitectureRegisters(self.handle, &mut count);
1129
1130            let ret = std::slice::from_raw_parts(registers_raw, count)
1131                .iter()
1132                .map(|&id| RegisterId::from(id))
1133                .filter_map(|reg| CoreRegister::new(*self, reg))
1134                .collect();
1135
1136            BNFreeRegisterList(registers_raw);
1137
1138            ret
1139        }
1140    }
1141
1142    fn register_from_id(&self, id: RegisterId) -> Option<CoreRegister> {
1143        CoreRegister::new(*self, id)
1144    }
1145
1146    fn registers_full_width(&self) -> Vec<CoreRegister> {
1147        unsafe {
1148            let mut count: usize = 0;
1149            let registers_raw = BNGetFullWidthArchitectureRegisters(self.handle, &mut count);
1150
1151            let ret = std::slice::from_raw_parts(registers_raw, count)
1152                .iter()
1153                .map(|&id| RegisterId::from(id))
1154                .filter_map(|reg| CoreRegister::new(*self, reg))
1155                .collect();
1156
1157            BNFreeRegisterList(registers_raw);
1158
1159            ret
1160        }
1161    }
1162
1163    fn registers_global(&self) -> Vec<CoreRegister> {
1164        unsafe {
1165            let mut count: usize = 0;
1166            let registers_raw = BNGetArchitectureGlobalRegisters(self.handle, &mut count);
1167
1168            let ret = std::slice::from_raw_parts(registers_raw, count)
1169                .iter()
1170                .map(|&id| RegisterId::from(id))
1171                .filter_map(|reg| CoreRegister::new(*self, reg))
1172                .collect();
1173
1174            BNFreeRegisterList(registers_raw);
1175
1176            ret
1177        }
1178    }
1179
1180    fn registers_system(&self) -> Vec<CoreRegister> {
1181        unsafe {
1182            let mut count: usize = 0;
1183            let registers_raw = BNGetArchitectureSystemRegisters(self.handle, &mut count);
1184
1185            let ret = std::slice::from_raw_parts(registers_raw, count)
1186                .iter()
1187                .map(|&id| RegisterId::from(id))
1188                .filter_map(|reg| CoreRegister::new(*self, reg))
1189                .collect();
1190
1191            BNFreeRegisterList(registers_raw);
1192
1193            ret
1194        }
1195    }
1196
1197    fn stack_pointer_reg(&self) -> Option<CoreRegister> {
1198        match unsafe { BNGetArchitectureStackPointerRegister(self.handle) } {
1199            INVALID_REGISTER => None,
1200            reg => Some(CoreRegister::new(*self, reg.into())?),
1201        }
1202    }
1203
1204    fn link_reg(&self) -> Option<CoreRegister> {
1205        match unsafe { BNGetArchitectureLinkRegister(self.handle) } {
1206            INVALID_REGISTER => None,
1207            reg => Some(CoreRegister::new(*self, reg.into())?),
1208        }
1209    }
1210
1211    fn register_stacks(&self) -> Vec<CoreRegisterStack> {
1212        unsafe {
1213            let mut count: usize = 0;
1214            let reg_stacks_raw = BNGetAllArchitectureRegisterStacks(self.handle, &mut count);
1215
1216            let ret = std::slice::from_raw_parts(reg_stacks_raw, count)
1217                .iter()
1218                .map(|&id| RegisterStackId::from(id))
1219                .filter_map(|reg_stack| CoreRegisterStack::new(*self, reg_stack))
1220                .collect();
1221
1222            BNFreeRegisterList(reg_stacks_raw);
1223
1224            ret
1225        }
1226    }
1227
1228    fn register_stack_from_id(&self, id: RegisterStackId) -> Option<CoreRegisterStack> {
1229        CoreRegisterStack::new(*self, id)
1230    }
1231
1232    fn flags(&self) -> Vec<CoreFlag> {
1233        unsafe {
1234            let mut count: usize = 0;
1235            let flags_raw = BNGetAllArchitectureFlags(self.handle, &mut count);
1236
1237            let ret = std::slice::from_raw_parts(flags_raw, count)
1238                .iter()
1239                .map(|&id| FlagId::from(id))
1240                .filter_map(|flag| CoreFlag::new(*self, flag))
1241                .collect();
1242
1243            BNFreeRegisterList(flags_raw);
1244
1245            ret
1246        }
1247    }
1248
1249    fn flag_from_id(&self, id: FlagId) -> Option<CoreFlag> {
1250        CoreFlag::new(*self, id)
1251    }
1252
1253    fn flag_write_types(&self) -> Vec<CoreFlagWrite> {
1254        unsafe {
1255            let mut count: usize = 0;
1256            let flag_writes_raw = BNGetAllArchitectureFlagWriteTypes(self.handle, &mut count);
1257
1258            let ret = std::slice::from_raw_parts(flag_writes_raw, count)
1259                .iter()
1260                .map(|&id| FlagWriteId::from(id))
1261                .filter_map(|flag_write| CoreFlagWrite::new(*self, flag_write))
1262                .collect();
1263
1264            BNFreeRegisterList(flag_writes_raw);
1265
1266            ret
1267        }
1268    }
1269
1270    fn flag_write_from_id(&self, id: FlagWriteId) -> Option<CoreFlagWrite> {
1271        CoreFlagWrite::new(*self, id)
1272    }
1273
1274    fn flag_classes(&self) -> Vec<CoreFlagClass> {
1275        unsafe {
1276            let mut count: usize = 0;
1277            let flag_classes_raw = BNGetAllArchitectureSemanticFlagClasses(self.handle, &mut count);
1278
1279            let ret = std::slice::from_raw_parts(flag_classes_raw, count)
1280                .iter()
1281                .map(|&id| FlagClassId::from(id))
1282                .filter_map(|flag_class| CoreFlagClass::new(*self, flag_class))
1283                .collect();
1284
1285            BNFreeRegisterList(flag_classes_raw);
1286
1287            ret
1288        }
1289    }
1290
1291    fn flag_class_from_id(&self, id: FlagClassId) -> Option<CoreFlagClass> {
1292        CoreFlagClass::new(*self, id)
1293    }
1294
1295    fn flag_groups(&self) -> Vec<CoreFlagGroup> {
1296        unsafe {
1297            let mut count: usize = 0;
1298            let flag_groups_raw = BNGetAllArchitectureSemanticFlagGroups(self.handle, &mut count);
1299
1300            let ret = std::slice::from_raw_parts(flag_groups_raw, count)
1301                .iter()
1302                .map(|&id| FlagGroupId::from(id))
1303                .filter_map(|flag_group| CoreFlagGroup::new(*self, flag_group))
1304                .collect();
1305
1306            BNFreeRegisterList(flag_groups_raw);
1307
1308            ret
1309        }
1310    }
1311
1312    fn flag_group_from_id(&self, id: FlagGroupId) -> Option<CoreFlagGroup> {
1313        CoreFlagGroup::new(*self, id)
1314    }
1315
1316    fn intrinsics(&self) -> Vec<CoreIntrinsic> {
1317        unsafe {
1318            let mut count: usize = 0;
1319            let intrinsics_raw = BNGetAllArchitectureIntrinsics(self.handle, &mut count);
1320
1321            let intrinsics = std::slice::from_raw_parts_mut(intrinsics_raw, count)
1322                .iter()
1323                .map(|&id| IntrinsicId::from(id))
1324                .filter_map(|intrinsic| CoreIntrinsic::new(*self, intrinsic))
1325                .collect();
1326
1327            BNFreeRegisterList(intrinsics_raw);
1328
1329            intrinsics
1330        }
1331    }
1332
1333    fn intrinsic_class(&self, id: IntrinsicId) -> BNIntrinsicClass {
1334        unsafe { BNGetArchitectureIntrinsicClass(self.handle, id.0) }
1335    }
1336
1337    fn intrinsic_from_id(&self, id: IntrinsicId) -> Option<CoreIntrinsic> {
1338        CoreIntrinsic::new(*self, id)
1339    }
1340
1341    fn can_assemble(&self) -> bool {
1342        unsafe { BNCanArchitectureAssemble(self.handle) }
1343    }
1344
1345    fn assemble(&self, code: &str, addr: u64) -> Result<Vec<u8>, String> {
1346        let code = CString::new(code).map_err(|_| "Invalid encoding in code string".to_string())?;
1347
1348        let result = DataBuffer::new(&[]);
1349        // TODO: This is actually a list of errors.
1350        let mut error_raw: *mut c_char = std::ptr::null_mut();
1351        let res = unsafe {
1352            BNAssemble(
1353                self.handle,
1354                code.as_ptr(),
1355                addr,
1356                result.as_raw(),
1357                &mut error_raw as *mut *mut c_char,
1358            )
1359        };
1360
1361        let error = raw_to_string(error_raw);
1362        unsafe {
1363            BNFreeString(error_raw);
1364        }
1365
1366        if res {
1367            Ok(result.get_data().to_vec())
1368        } else {
1369            Err(error.unwrap_or_else(|| "Assemble failed".into()))
1370        }
1371    }
1372
1373    fn is_never_branch_patch_available(&self, data: &[u8], addr: u64) -> bool {
1374        unsafe {
1375            BNIsArchitectureNeverBranchPatchAvailable(self.handle, data.as_ptr(), addr, data.len())
1376        }
1377    }
1378
1379    fn is_always_branch_patch_available(&self, data: &[u8], addr: u64) -> bool {
1380        unsafe {
1381            BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, data.as_ptr(), addr, data.len())
1382        }
1383    }
1384
1385    fn is_invert_branch_patch_available(&self, data: &[u8], addr: u64) -> bool {
1386        unsafe {
1387            BNIsArchitectureInvertBranchPatchAvailable(self.handle, data.as_ptr(), addr, data.len())
1388        }
1389    }
1390
1391    fn is_skip_and_return_zero_patch_available(&self, data: &[u8], addr: u64) -> bool {
1392        unsafe {
1393            BNIsArchitectureSkipAndReturnZeroPatchAvailable(
1394                self.handle,
1395                data.as_ptr(),
1396                addr,
1397                data.len(),
1398            )
1399        }
1400    }
1401
1402    fn is_skip_and_return_value_patch_available(&self, data: &[u8], addr: u64) -> bool {
1403        unsafe {
1404            BNIsArchitectureSkipAndReturnValuePatchAvailable(
1405                self.handle,
1406                data.as_ptr(),
1407                addr,
1408                data.len(),
1409            )
1410        }
1411    }
1412
1413    fn convert_to_nop(&self, data: &mut [u8], addr: u64) -> bool {
1414        unsafe { BNArchitectureConvertToNop(self.handle, data.as_mut_ptr(), addr, data.len()) }
1415    }
1416
1417    fn always_branch(&self, data: &mut [u8], addr: u64) -> bool {
1418        unsafe { BNArchitectureAlwaysBranch(self.handle, data.as_mut_ptr(), addr, data.len()) }
1419    }
1420
1421    fn invert_branch(&self, data: &mut [u8], addr: u64) -> bool {
1422        unsafe { BNArchitectureInvertBranch(self.handle, data.as_mut_ptr(), addr, data.len()) }
1423    }
1424
1425    fn skip_and_return_value(&self, data: &mut [u8], addr: u64, value: u64) -> bool {
1426        unsafe {
1427            BNArchitectureSkipAndReturnValue(
1428                self.handle,
1429                data.as_mut_ptr(),
1430                addr,
1431                data.len(),
1432                value,
1433            )
1434        }
1435    }
1436
1437    fn handle(&self) -> CoreArchitecture {
1438        *self
1439    }
1440}
1441
1442impl Debug for CoreArchitecture {
1443    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1444        f.debug_struct("CoreArchitecture")
1445            .field("name", &self.name())
1446            .field("endianness", &self.endianness())
1447            .field("address_size", &self.address_size())
1448            .field("instruction_alignment", &self.instruction_alignment())
1449            .finish()
1450    }
1451}
1452
1453macro_rules! cc_func {
1454    ($get_name:ident, $get_api:ident, $set_name:ident, $set_api:ident) => {
1455        fn $get_name(&self) -> Option<Ref<CoreCallingConvention>> {
1456            let arch = self.as_ref();
1457
1458            unsafe {
1459                let cc = $get_api(arch.handle);
1460
1461                if cc.is_null() {
1462                    None
1463                } else {
1464                    Some(CoreCallingConvention::ref_from_raw(
1465                        cc,
1466                        self.as_ref().handle(),
1467                    ))
1468                }
1469            }
1470        }
1471
1472        fn $set_name(&self, cc: &CoreCallingConvention) {
1473            let arch = self.as_ref();
1474
1475            assert!(
1476                cc.arch_handle.borrow().as_ref().handle == arch.handle,
1477                "use of calling convention with non-matching architecture!"
1478            );
1479
1480            unsafe {
1481                $set_api(arch.handle, cc.handle);
1482            }
1483        }
1484    };
1485}
1486
1487/// Contains helper methods for all types implementing 'Architecture'
1488pub trait ArchitectureExt: Architecture {
1489    fn register_by_name(&self, name: &str) -> Option<Self::Register> {
1490        let name = name.to_cstr();
1491
1492        match unsafe { BNGetArchitectureRegisterByName(self.as_ref().handle, name.as_ptr()) } {
1493            INVALID_REGISTER => None,
1494            reg => self.register_from_id(reg.into()),
1495        }
1496    }
1497
1498    fn calling_convention_by_name(&self, name: &str) -> Option<Ref<CoreCallingConvention>> {
1499        let name = name.to_cstr();
1500        unsafe {
1501            let result = NonNull::new(BNGetArchitectureCallingConventionByName(
1502                self.as_ref().handle,
1503                name.as_ptr(),
1504            ))?;
1505            Some(CoreCallingConvention::ref_from_raw(
1506                result.as_ptr(),
1507                self.as_ref().handle(),
1508            ))
1509        }
1510    }
1511
1512    fn calling_conventions(&self) -> Array<CoreCallingConvention> {
1513        unsafe {
1514            let mut count = 0;
1515            let calling_convs =
1516                BNGetArchitectureCallingConventions(self.as_ref().handle, &mut count);
1517            Array::new(calling_convs, count, self.as_ref().handle())
1518        }
1519    }
1520
1521    cc_func!(
1522        get_default_calling_convention,
1523        BNGetArchitectureDefaultCallingConvention,
1524        set_default_calling_convention,
1525        BNSetArchitectureDefaultCallingConvention
1526    );
1527
1528    cc_func!(
1529        get_cdecl_calling_convention,
1530        BNGetArchitectureCdeclCallingConvention,
1531        set_cdecl_calling_convention,
1532        BNSetArchitectureCdeclCallingConvention
1533    );
1534
1535    cc_func!(
1536        get_stdcall_calling_convention,
1537        BNGetArchitectureStdcallCallingConvention,
1538        set_stdcall_calling_convention,
1539        BNSetArchitectureStdcallCallingConvention
1540    );
1541
1542    cc_func!(
1543        get_fastcall_calling_convention,
1544        BNGetArchitectureFastcallCallingConvention,
1545        set_fastcall_calling_convention,
1546        BNSetArchitectureFastcallCallingConvention
1547    );
1548
1549    fn standalone_platform(&self) -> Option<Ref<Platform>> {
1550        unsafe {
1551            let handle = BNGetArchitectureStandalonePlatform(self.as_ref().handle);
1552
1553            if handle.is_null() {
1554                return None;
1555            }
1556
1557            Some(Platform::ref_from_raw(handle))
1558        }
1559    }
1560
1561    fn relocation_handler(&self, view_name: &str) -> Option<Ref<CoreRelocationHandler>> {
1562        let view_name = match CString::new(view_name) {
1563            Ok(view_name) => view_name,
1564            Err(_) => return None,
1565        };
1566
1567        unsafe {
1568            let handle =
1569                BNArchitectureGetRelocationHandler(self.as_ref().handle, view_name.as_ptr());
1570
1571            if handle.is_null() {
1572                return None;
1573            }
1574
1575            Some(CoreRelocationHandler::ref_from_raw(handle))
1576        }
1577    }
1578
1579    fn register_relocation_handler<R, F>(&self, name: &str, func: F)
1580    where
1581        R: 'static
1582            + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>>
1583            + Send
1584            + Sync
1585            + Sized,
1586        F: FnOnce(CustomRelocationHandlerHandle<R>, CoreRelocationHandler) -> R,
1587    {
1588        crate::relocation::register_relocation_handler(self.as_ref(), name, func);
1589    }
1590
1591    fn register_function_recognizer<R>(&self, recognizer: R)
1592    where
1593        R: 'static + FunctionRecognizer + Send + Sync + Sized,
1594    {
1595        crate::function_recognizer::register_arch_function_recognizer(self.as_ref(), recognizer);
1596    }
1597}
1598
1599impl<T: Architecture> ArchitectureExt for T {}
1600
1601/// Registers a new architecture with the given name.
1602///
1603/// NOTE: This function should only be called within `CorePluginInit`.
1604pub fn register_architecture<A, F>(name: &str, func: F) -> &'static A
1605where
1606    A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync + Sized,
1607    F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
1608{
1609    register_architecture_impl(ArchitectureRegistration::New(name), func, |_| {})
1610}
1611
1612enum ArchitectureRegistration<'a> {
1613    New(&'a str),
1614    Hook(CoreArchitecture),
1615}
1616
1617fn register_architecture_impl<A, F, C>(
1618    registration: ArchitectureRegistration<'_>,
1619    func: F,
1620    customize: C,
1621) -> &'static A
1622where
1623    A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync + Sized,
1624    F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
1625    C: FnOnce(&mut BNCustomArchitecture),
1626{
1627    #[repr(C)]
1628    struct ArchitectureBuilder<A, F>
1629    where
1630        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1631        F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
1632    {
1633        arch: MaybeUninit<A>,
1634        func: Option<F>,
1635    }
1636
1637    extern "C" fn cb_init<A, F>(ctxt: *mut c_void, obj: *mut BNArchitecture)
1638    where
1639        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1640        F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
1641    {
1642        unsafe {
1643            let custom_arch = &mut *(ctxt as *mut ArchitectureBuilder<A, F>);
1644            let custom_arch_handle = CustomArchitectureHandle {
1645                handle: ctxt as *mut A,
1646            };
1647
1648            let create = custom_arch.func.take().unwrap();
1649            custom_arch
1650                .arch
1651                .write(create(custom_arch_handle, CoreArchitecture::from_raw(obj)));
1652        }
1653    }
1654
1655    extern "C" fn cb_endianness<A>(ctxt: *mut c_void) -> BNEndianness
1656    where
1657        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1658    {
1659        let custom_arch = unsafe { &*(ctxt as *mut A) };
1660        custom_arch.endianness()
1661    }
1662
1663    extern "C" fn cb_address_size<A>(ctxt: *mut c_void) -> usize
1664    where
1665        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1666    {
1667        let custom_arch = unsafe { &*(ctxt as *mut A) };
1668        custom_arch.address_size()
1669    }
1670
1671    extern "C" fn cb_default_integer_size<A>(ctxt: *mut c_void) -> usize
1672    where
1673        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1674    {
1675        let custom_arch = unsafe { &*(ctxt as *mut A) };
1676        custom_arch.default_integer_size()
1677    }
1678
1679    extern "C" fn cb_instruction_alignment<A>(ctxt: *mut c_void) -> usize
1680    where
1681        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1682    {
1683        let custom_arch = unsafe { &*(ctxt as *mut A) };
1684        custom_arch.instruction_alignment()
1685    }
1686
1687    extern "C" fn cb_linear_sweep_initial_alignment<A>(ctxt: *mut c_void) -> usize
1688    where
1689        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1690    {
1691        let custom_arch = unsafe { &*(ctxt as *mut A) };
1692        custom_arch.linear_sweep_initial_alignment()
1693    }
1694
1695    extern "C" fn cb_linear_sweep_analysis_capabilities<A>(ctxt: *mut c_void) -> u32
1696    where
1697        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1698    {
1699        let custom_arch = unsafe { &*(ctxt as *mut A) };
1700        custom_arch.linear_sweep_analysis_capabilities()
1701    }
1702
1703    extern "C" fn cb_max_instr_len<A>(ctxt: *mut c_void) -> usize
1704    where
1705        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1706    {
1707        let custom_arch = unsafe { &*(ctxt as *mut A) };
1708        custom_arch.max_instr_len()
1709    }
1710
1711    extern "C" fn cb_opcode_display_len<A>(ctxt: *mut c_void) -> usize
1712    where
1713        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1714    {
1715        let custom_arch = unsafe { &*(ctxt as *mut A) };
1716        custom_arch.opcode_display_len()
1717    }
1718
1719    extern "C" fn cb_associated_arch_by_addr<A>(
1720        ctxt: *mut c_void,
1721        addr: *mut u64,
1722    ) -> *mut BNArchitecture
1723    where
1724        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1725    {
1726        let custom_arch = unsafe { &*(ctxt as *mut A) };
1727        let addr = unsafe { &mut *addr };
1728
1729        custom_arch.associated_arch_by_addr(addr).handle
1730    }
1731
1732    extern "C" fn cb_instruction_info<A>(
1733        ctxt: *mut c_void,
1734        data: *const u8,
1735        addr: u64,
1736        len: usize,
1737        result: *mut BNInstructionInfo,
1738    ) -> bool
1739    where
1740        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1741    {
1742        let custom_arch = unsafe { &*(ctxt as *mut A) };
1743        let data = unsafe { std::slice::from_raw_parts(data, len) };
1744
1745        match custom_arch.instruction_info(data, addr) {
1746            Some(info) => {
1747                // SAFETY: Passed in to be written to
1748                unsafe { *result = info.into() };
1749                true
1750            }
1751            None => false,
1752        }
1753    }
1754
1755    extern "C" fn cb_get_instruction_text<A>(
1756        ctxt: *mut c_void,
1757        data: *const u8,
1758        addr: u64,
1759        len: *mut usize,
1760        result: *mut *mut BNInstructionTextToken,
1761        count: *mut usize,
1762    ) -> bool
1763    where
1764        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1765    {
1766        let custom_arch = unsafe { &*(ctxt as *mut A) };
1767        let data = unsafe { std::slice::from_raw_parts(data, *len) };
1768        let result = unsafe { &mut *result };
1769
1770        let Some((res_size, res_tokens)) = custom_arch.instruction_text(data, addr) else {
1771            return false;
1772        };
1773
1774        let res_tokens: Box<[BNInstructionTextToken]> = res_tokens
1775            .into_iter()
1776            .map(InstructionTextToken::into_raw)
1777            .collect();
1778        unsafe {
1779            // NOTE: Freed with `cb_free_instruction_text`
1780            let res_tokens = Box::leak(res_tokens);
1781            *result = res_tokens.as_mut_ptr();
1782            *count = res_tokens.len();
1783            *len = res_size;
1784        }
1785        true
1786    }
1787
1788    pub unsafe extern "C" fn cb_get_instruction_text_with_context<A>(
1789        ctxt: *mut c_void,
1790        data: *const u8,
1791        addr: u64,
1792        len: *mut usize,
1793        context: *mut c_void,
1794        result: *mut *mut BNInstructionTextToken,
1795        count: *mut usize,
1796    ) -> bool
1797    where
1798        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1799    {
1800        let custom_arch = unsafe { &*(ctxt as *mut A) };
1801        let data = unsafe { std::slice::from_raw_parts(data, *len) };
1802        let result = unsafe { &mut *result };
1803        let context = NonNull::new(context);
1804
1805        let Some((res_size, res_tokens)) =
1806            custom_arch.instruction_text_with_context(data, addr, context)
1807        else {
1808            return false;
1809        };
1810
1811        let res_tokens: Box<[BNInstructionTextToken]> = res_tokens
1812            .into_iter()
1813            .map(InstructionTextToken::into_raw)
1814            .collect();
1815        unsafe {
1816            // NOTE: Freed with `cb_free_instruction_text`
1817            let res_tokens = Box::leak(res_tokens);
1818            *result = res_tokens.as_mut_ptr();
1819            *count = res_tokens.len();
1820            *len = res_size;
1821        }
1822        true
1823    }
1824
1825    extern "C" fn cb_free_instruction_text(tokens: *mut BNInstructionTextToken, count: usize) {
1826        unsafe {
1827            let raw_tokens = std::slice::from_raw_parts_mut(tokens, count);
1828            let boxed_tokens = Box::from_raw(raw_tokens);
1829            for token in boxed_tokens {
1830                InstructionTextToken::free_raw(token);
1831            }
1832        }
1833    }
1834
1835    extern "C" fn cb_instruction_llil<A>(
1836        ctxt: *mut c_void,
1837        data: *const u8,
1838        addr: u64,
1839        len: *mut usize,
1840        il: *mut BNLowLevelILFunction,
1841    ) -> bool
1842    where
1843        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1844    {
1845        let custom_arch = unsafe { &*(ctxt as *mut A) };
1846        let data = unsafe { std::slice::from_raw_parts(data, *len) };
1847        let lifter = unsafe {
1848            LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref()))
1849        };
1850
1851        match custom_arch.instruction_llil(data, addr, &lifter) {
1852            Some((res_len, res_value)) => {
1853                unsafe { *len = res_len };
1854                res_value
1855            }
1856            None => false,
1857        }
1858    }
1859
1860    extern "C" fn cb_supports_standalone_instruction_decoding<A>(ctxt: *mut c_void) -> bool
1861    where
1862        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1863    {
1864        let custom_arch = unsafe { &*(ctxt as *mut A) };
1865        custom_arch.supports_standalone_instruction_decoding()
1866    }
1867
1868    extern "C" fn cb_analyze_basic_blocks<A>(
1869        ctxt: *mut c_void,
1870        function: *mut BNFunction,
1871        context: *mut BNBasicBlockAnalysisContext,
1872    ) where
1873        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1874    {
1875        let custom_arch = unsafe { &*(ctxt as *mut A) };
1876        let mut function = unsafe { Function::from_raw(function) };
1877        let mut context: BasicBlockAnalysisContext =
1878            unsafe { BasicBlockAnalysisContext::from_raw(context) };
1879        custom_arch.analyze_basic_blocks(&mut function, &mut context);
1880    }
1881
1882    extern "C" fn cb_lift_function<A>(
1883        ctxt: *mut c_void,
1884        function: *mut BNLowLevelILFunction,
1885        context: *mut BNFunctionLifterContext,
1886    ) -> bool
1887    where
1888        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1889    {
1890        let custom_arch = unsafe { &*(ctxt as *mut A) };
1891        let llil = unsafe {
1892            LowLevelILMutableFunction::from_raw_with_arch(function, Some(*custom_arch.as_ref()))
1893        };
1894
1895        let mut ctx = unsafe {
1896            FunctionLifterContext::from_raw_with_arch(
1897                function,
1898                context,
1899                Some(*custom_arch.as_ref()),
1900            )
1901        };
1902        custom_arch.lift_function(llil, &mut ctx)
1903    }
1904
1905    extern "C" fn cb_reg_name<A>(ctxt: *mut c_void, reg: u32) -> *mut c_char
1906    where
1907        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1908    {
1909        let custom_arch = unsafe { &*(ctxt as *mut A) };
1910
1911        match custom_arch.register_from_id(reg.into()) {
1912            Some(reg) => BnString::into_raw(BnString::new(reg.name().as_ref())),
1913            None => BnString::into_raw(BnString::new("invalid_reg")),
1914        }
1915    }
1916
1917    extern "C" fn cb_flag_name<A>(ctxt: *mut c_void, flag: u32) -> *mut c_char
1918    where
1919        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1920    {
1921        let custom_arch = unsafe { &*(ctxt as *mut A) };
1922
1923        match custom_arch.flag_from_id(flag.into()) {
1924            Some(flag) => BnString::into_raw(BnString::new(flag.name().as_ref())),
1925            None => BnString::into_raw(BnString::new("invalid_flag")),
1926        }
1927    }
1928
1929    extern "C" fn cb_flag_write_name<A>(ctxt: *mut c_void, flag_write: u32) -> *mut c_char
1930    where
1931        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1932    {
1933        let custom_arch = unsafe { &*(ctxt as *mut A) };
1934
1935        match custom_arch.flag_write_from_id(flag_write.into()) {
1936            Some(flag_write) => BnString::into_raw(BnString::new(flag_write.name().as_ref())),
1937            None => BnString::into_raw(BnString::new("invalid_flag_write")),
1938        }
1939    }
1940
1941    extern "C" fn cb_semantic_flag_class_name<A>(ctxt: *mut c_void, class: u32) -> *mut c_char
1942    where
1943        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1944    {
1945        let custom_arch = unsafe { &*(ctxt as *mut A) };
1946
1947        match custom_arch.flag_class_from_id(class.into()) {
1948            Some(class) => BnString::into_raw(BnString::new(class.name().as_ref())),
1949            None => BnString::into_raw(BnString::new("invalid_flag_class")),
1950        }
1951    }
1952
1953    extern "C" fn cb_semantic_flag_group_name<A>(ctxt: *mut c_void, group: u32) -> *mut c_char
1954    where
1955        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1956    {
1957        let custom_arch = unsafe { &*(ctxt as *mut A) };
1958
1959        match custom_arch.flag_group_from_id(group.into()) {
1960            Some(group) => BnString::into_raw(BnString::new(group.name().as_ref())),
1961            None => BnString::into_raw(BnString::new("invalid_flag_group")),
1962        }
1963    }
1964
1965    extern "C" fn cb_registers_full_width<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
1966    where
1967        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1968    {
1969        let custom_arch = unsafe { &*(ctxt as *mut A) };
1970        let mut regs: Box<[_]> = custom_arch
1971            .registers_full_width()
1972            .iter()
1973            .map(|r| r.id().0)
1974            .collect();
1975
1976        // SAFETY: `count` is an out parameter
1977        unsafe { *count = regs.len() };
1978        let regs_ptr = regs.as_mut_ptr();
1979        std::mem::forget(regs);
1980        regs_ptr
1981    }
1982
1983    extern "C" fn cb_registers_all<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
1984    where
1985        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
1986    {
1987        let custom_arch = unsafe { &*(ctxt as *mut A) };
1988        let mut regs: Box<[_]> = custom_arch
1989            .registers_all()
1990            .iter()
1991            .map(|r| r.id().0)
1992            .collect();
1993
1994        // SAFETY: `count` is an out parameter
1995        unsafe { *count = regs.len() };
1996        let regs_ptr = regs.as_mut_ptr();
1997        std::mem::forget(regs);
1998        regs_ptr
1999    }
2000
2001    extern "C" fn cb_registers_global<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2002    where
2003        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2004    {
2005        let custom_arch = unsafe { &*(ctxt as *mut A) };
2006        let mut regs: Box<[_]> = custom_arch
2007            .registers_global()
2008            .iter()
2009            .map(|r| r.id().0)
2010            .collect();
2011
2012        // SAFETY: `count` is an out parameter
2013        unsafe { *count = regs.len() };
2014        let regs_ptr = regs.as_mut_ptr();
2015        std::mem::forget(regs);
2016        regs_ptr
2017    }
2018
2019    extern "C" fn cb_registers_system<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2020    where
2021        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2022    {
2023        let custom_arch = unsafe { &*(ctxt as *mut A) };
2024        let mut regs: Box<[_]> = custom_arch
2025            .registers_system()
2026            .iter()
2027            .map(|r| r.id().0)
2028            .collect();
2029
2030        // SAFETY: `count` is an out parameter
2031        unsafe { *count = regs.len() };
2032        let regs_ptr = regs.as_mut_ptr();
2033        std::mem::forget(regs);
2034        regs_ptr
2035    }
2036
2037    extern "C" fn cb_flags<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2038    where
2039        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2040    {
2041        let custom_arch = unsafe { &*(ctxt as *mut A) };
2042        let mut flags: Box<[_]> = custom_arch.flags().iter().map(|f| f.id().0).collect();
2043
2044        // SAFETY: `count` is an out parameter
2045        unsafe { *count = flags.len() };
2046        let flags_ptr = flags.as_mut_ptr();
2047        std::mem::forget(flags);
2048        flags_ptr
2049    }
2050
2051    extern "C" fn cb_flag_write_types<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2052    where
2053        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2054    {
2055        let custom_arch = unsafe { &*(ctxt as *mut A) };
2056        let mut flag_writes: Box<[_]> = custom_arch
2057            .flag_write_types()
2058            .iter()
2059            .map(|f| f.id().0)
2060            .collect();
2061
2062        // SAFETY: `count` is an out parameter
2063        unsafe { *count = flag_writes.len() };
2064        let flags_ptr = flag_writes.as_mut_ptr();
2065        std::mem::forget(flag_writes);
2066        flags_ptr
2067    }
2068
2069    extern "C" fn cb_semantic_flag_classes<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2070    where
2071        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2072    {
2073        let custom_arch = unsafe { &*(ctxt as *mut A) };
2074        let mut flag_classes: Box<[_]> = custom_arch
2075            .flag_classes()
2076            .iter()
2077            .map(|f| f.id().0)
2078            .collect();
2079
2080        // SAFETY: `count` is an out parameter
2081        unsafe { *count = flag_classes.len() };
2082        let flags_ptr = flag_classes.as_mut_ptr();
2083        std::mem::forget(flag_classes);
2084        flags_ptr
2085    }
2086
2087    extern "C" fn cb_semantic_flag_groups<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2088    where
2089        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2090    {
2091        let custom_arch = unsafe { &*(ctxt as *mut A) };
2092        let mut flag_groups: Box<[_]> =
2093            custom_arch.flag_groups().iter().map(|f| f.id().0).collect();
2094
2095        // SAFETY: `count` is an out parameter
2096        unsafe { *count = flag_groups.len() };
2097        let flags_ptr = flag_groups.as_mut_ptr();
2098        std::mem::forget(flag_groups);
2099        flags_ptr
2100    }
2101
2102    extern "C" fn cb_flag_role<A>(ctxt: *mut c_void, flag: u32, class: u32) -> BNFlagRole
2103    where
2104        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2105    {
2106        let custom_arch = unsafe { &*(ctxt as *mut A) };
2107
2108        if let (Some(flag), class) = (
2109            custom_arch.flag_from_id(FlagId(flag)),
2110            custom_arch.flag_class_from_id(FlagClassId(class)),
2111        ) {
2112            flag.role(class)
2113        } else {
2114            FlagRole::SpecialFlagRole
2115        }
2116    }
2117
2118    extern "C" fn cb_flags_required_for_flag_cond<A>(
2119        ctxt: *mut c_void,
2120        cond: BNLowLevelILFlagCondition,
2121        class: u32,
2122        count: *mut usize,
2123    ) -> *mut u32
2124    where
2125        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2126    {
2127        let custom_arch = unsafe { &*(ctxt as *mut A) };
2128        let class = custom_arch.flag_class_from_id(FlagClassId(class));
2129        let mut flags: Box<[_]> = custom_arch
2130            .flags_required_for_flag_condition(cond, class)
2131            .iter()
2132            .map(|f| f.id().0)
2133            .collect();
2134
2135        // SAFETY: `count` is an out parameter
2136        unsafe { *count = flags.len() };
2137        let flags_ptr = flags.as_mut_ptr();
2138        std::mem::forget(flags);
2139        flags_ptr
2140    }
2141
2142    extern "C" fn cb_flags_required_for_semantic_flag_group<A>(
2143        ctxt: *mut c_void,
2144        group: u32,
2145        count: *mut usize,
2146    ) -> *mut u32
2147    where
2148        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2149    {
2150        let custom_arch = unsafe { &*(ctxt as *mut A) };
2151
2152        if let Some(group) = custom_arch.flag_group_from_id(FlagGroupId(group)) {
2153            let mut flags: Box<[_]> = group.flags_required().iter().map(|f| f.id().0).collect();
2154
2155            // SAFETY: `count` is an out parameter
2156            unsafe { *count = flags.len() };
2157            let flags_ptr = flags.as_mut_ptr();
2158            std::mem::forget(flags);
2159            flags_ptr
2160        } else {
2161            unsafe {
2162                *count = 0;
2163            }
2164            std::ptr::null_mut()
2165        }
2166    }
2167
2168    extern "C" fn cb_flag_conditions_for_semantic_flag_group<A>(
2169        ctxt: *mut c_void,
2170        group: u32,
2171        count: *mut usize,
2172    ) -> *mut BNFlagConditionForSemanticClass
2173    where
2174        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2175    {
2176        let custom_arch = unsafe { &*(ctxt as *mut A) };
2177
2178        if let Some(group) = custom_arch.flag_group_from_id(FlagGroupId(group)) {
2179            let flag_conditions = group.flag_conditions();
2180            let mut flags: Box<[_]> = flag_conditions
2181                .iter()
2182                .map(|(&class, &condition)| BNFlagConditionForSemanticClass {
2183                    semanticClass: class.id().0,
2184                    condition,
2185                })
2186                .collect();
2187
2188            // SAFETY: `count` is an out parameter
2189            unsafe { *count = flags.len() };
2190            let flags_ptr = flags.as_mut_ptr();
2191            std::mem::forget(flags);
2192            flags_ptr
2193        } else {
2194            unsafe {
2195                *count = 0;
2196            }
2197            std::ptr::null_mut()
2198        }
2199    }
2200
2201    extern "C" fn cb_free_flag_conditions_for_semantic_flag_group<A>(
2202        _ctxt: *mut c_void,
2203        conds: *mut BNFlagConditionForSemanticClass,
2204        count: usize,
2205    ) where
2206        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2207    {
2208        if conds.is_null() {
2209            return;
2210        }
2211
2212        unsafe {
2213            let flags_ptr = std::ptr::slice_from_raw_parts_mut(conds, count);
2214            let _flags = Box::from_raw(flags_ptr);
2215        }
2216    }
2217
2218    extern "C" fn cb_flags_written_by_write_type<A>(
2219        ctxt: *mut c_void,
2220        write_type: u32,
2221        count: *mut usize,
2222    ) -> *mut u32
2223    where
2224        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2225    {
2226        let custom_arch = unsafe { &*(ctxt as *mut A) };
2227
2228        if let Some(write_type) = custom_arch.flag_write_from_id(FlagWriteId(write_type)) {
2229            let mut flags_written: Box<[_]> = write_type
2230                .flags_written()
2231                .iter()
2232                .map(|f| f.id().0)
2233                .collect();
2234
2235            // SAFETY: `count` is an out parameter
2236            unsafe { *count = flags_written.len() };
2237            let flags_ptr = flags_written.as_mut_ptr();
2238            std::mem::forget(flags_written);
2239            flags_ptr
2240        } else {
2241            unsafe {
2242                *count = 0;
2243            }
2244            std::ptr::null_mut()
2245        }
2246    }
2247
2248    extern "C" fn cb_semantic_class_for_flag_write_type<A>(
2249        ctxt: *mut c_void,
2250        write_type: u32,
2251    ) -> u32
2252    where
2253        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2254    {
2255        let custom_arch = unsafe { &*(ctxt as *mut A) };
2256        custom_arch
2257            .flag_write_from_id(FlagWriteId(write_type))
2258            .map(|w| w.class())
2259            .and_then(|c| c.map(|c| c.id().0))
2260            .unwrap_or(0)
2261    }
2262
2263    extern "C" fn cb_flag_write_llil<A>(
2264        ctxt: *mut c_void,
2265        op: BNLowLevelILOperation,
2266        size: usize,
2267        flag_write: u32,
2268        flag: u32,
2269        operands_raw: *mut BNRegisterOrConstant,
2270        operand_count: usize,
2271        il: *mut BNLowLevelILFunction,
2272    ) -> usize
2273    where
2274        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2275    {
2276        let custom_arch = unsafe { &*(ctxt as *mut A) };
2277        let flag_write_type = custom_arch.flag_write_from_id(FlagWriteId(flag_write));
2278        let flag_value = custom_arch.flag_from_id(FlagId(flag));
2279        let operands = if operand_count == 0 {
2280            &[]
2281        } else {
2282            unsafe { std::slice::from_raw_parts(operands_raw, operand_count) }
2283        };
2284        let lifter = unsafe {
2285            LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref()))
2286        };
2287
2288        if let (Some(flag_write_type), Some(flag_value)) = (flag_write_type, flag_value) {
2289            let decoded_op = LowLevelILFlagWriteOp::from_op(custom_arch, size, op, operands);
2290            if let Some(expr) =
2291                custom_arch.flag_write_llil(flag_value, flag_write_type, decoded_op, &lifter)
2292            {
2293                // TODO verify that returned expr is a bool value
2294                return expr.index.0;
2295            }
2296
2297            let role = flag_value.role(flag_write_type.class());
2298
2299            unsafe {
2300                BNGetDefaultArchitectureFlagWriteLowLevelIL(
2301                    custom_arch.as_ref().handle,
2302                    op,
2303                    size,
2304                    role,
2305                    operands_raw,
2306                    operand_count,
2307                    il,
2308                )
2309            }
2310        } else {
2311            // TODO this should be impossible; requires bad flag/flag_write ids passed in;
2312            // explode more violently
2313            lifter.unimplemented().index.0
2314        }
2315    }
2316
2317    extern "C" fn cb_flag_cond_llil<A>(
2318        ctxt: *mut c_void,
2319        cond: FlagCondition,
2320        class: u32,
2321        il: *mut BNLowLevelILFunction,
2322    ) -> usize
2323    where
2324        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2325    {
2326        let custom_arch = unsafe { &*(ctxt as *mut A) };
2327        let class = custom_arch.flag_class_from_id(FlagClassId(class));
2328
2329        let lifter = unsafe {
2330            LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref()))
2331        };
2332        if let Some(expr) = custom_arch.flag_cond_llil(cond, class, &lifter) {
2333            // TODO verify that returned expr is a bool value
2334            return expr.index.0;
2335        }
2336
2337        lifter.unimplemented().index.0
2338    }
2339
2340    extern "C" fn cb_flag_group_llil<A>(
2341        ctxt: *mut c_void,
2342        group: u32,
2343        il: *mut BNLowLevelILFunction,
2344    ) -> usize
2345    where
2346        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2347    {
2348        let custom_arch = unsafe { &*(ctxt as *mut A) };
2349        let lifter = unsafe {
2350            LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref()))
2351        };
2352
2353        if let Some(group) = custom_arch.flag_group_from_id(FlagGroupId(group)) {
2354            if let Some(expr) = custom_arch.flag_group_llil(group, &lifter) {
2355                // TODO verify that returned expr is a bool value
2356                return expr.index.0;
2357            }
2358        }
2359
2360        lifter.unimplemented().index.0
2361    }
2362
2363    extern "C" fn cb_free_register_list(_ctxt: *mut c_void, regs: *mut u32, count: usize) {
2364        if regs.is_null() {
2365            return;
2366        }
2367
2368        unsafe {
2369            let regs_ptr = std::ptr::slice_from_raw_parts_mut(regs, count);
2370            let _regs = Box::from_raw(regs_ptr);
2371        }
2372    }
2373
2374    extern "C" fn cb_register_info<A>(ctxt: *mut c_void, reg: u32, result: *mut BNRegisterInfo)
2375    where
2376        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2377    {
2378        let custom_arch = unsafe { &*(ctxt as *mut A) };
2379        let result = unsafe { &mut *result };
2380
2381        if let Some(reg) = custom_arch.register_from_id(RegisterId(reg)) {
2382            let info = reg.info();
2383
2384            result.fullWidthRegister = match info.parent() {
2385                Some(p) => p.id().0,
2386                None => reg.id().0,
2387            };
2388
2389            result.offset = info.offset();
2390            result.size = info.size();
2391            result.extend = info.implicit_extend().into();
2392        }
2393    }
2394
2395    extern "C" fn cb_stack_pointer<A>(ctxt: *mut c_void) -> u32
2396    where
2397        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2398    {
2399        let custom_arch = unsafe { &*(ctxt as *mut A) };
2400
2401        if let Some(reg) = custom_arch.stack_pointer_reg() {
2402            reg.id().0
2403        } else {
2404            INVALID_REGISTER
2405        }
2406    }
2407
2408    extern "C" fn cb_link_reg<A>(ctxt: *mut c_void) -> u32
2409    where
2410        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2411    {
2412        let custom_arch = unsafe { &*(ctxt as *mut A) };
2413
2414        if let Some(reg) = custom_arch.link_reg() {
2415            reg.id().0
2416        } else {
2417            INVALID_REGISTER
2418        }
2419    }
2420
2421    extern "C" fn cb_reg_stack_name<A>(ctxt: *mut c_void, stack: u32) -> *mut c_char
2422    where
2423        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2424    {
2425        let custom_arch = unsafe { &*(ctxt as *mut A) };
2426
2427        match custom_arch.register_stack_from_id(RegisterStackId(stack)) {
2428            Some(stack) => BnString::into_raw(BnString::new(stack.name().as_ref())),
2429            None => BnString::into_raw(BnString::new("invalid_reg_stack")),
2430        }
2431    }
2432
2433    extern "C" fn cb_reg_stacks<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2434    where
2435        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2436    {
2437        let custom_arch = unsafe { &*(ctxt as *mut A) };
2438        let mut regs: Box<[_]> = custom_arch
2439            .register_stacks()
2440            .iter()
2441            .map(|r| r.id().0)
2442            .collect();
2443
2444        // SAFETY: Passed in to be written
2445        unsafe { *count = regs.len() };
2446        let regs_ptr = regs.as_mut_ptr();
2447        std::mem::forget(regs);
2448        regs_ptr
2449    }
2450
2451    extern "C" fn cb_reg_stack_info<A>(
2452        ctxt: *mut c_void,
2453        stack: u32,
2454        result: *mut BNRegisterStackInfo,
2455    ) where
2456        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2457    {
2458        let custom_arch = unsafe { &*(ctxt as *mut A) };
2459        let result = unsafe { &mut *result };
2460
2461        if let Some(stack) = custom_arch.register_stack_from_id(RegisterStackId(stack)) {
2462            let info = stack.info();
2463
2464            let (reg, count) = info.storage_regs();
2465            result.firstStorageReg = reg.id().0;
2466            result.storageCount = count as u32;
2467
2468            if let Some((reg, count)) = info.top_relative_regs() {
2469                result.firstTopRelativeReg = reg.id().0;
2470                result.topRelativeCount = count as u32;
2471            } else {
2472                result.firstTopRelativeReg = INVALID_REGISTER;
2473                result.topRelativeCount = 0;
2474            }
2475
2476            result.stackTopReg = info.stack_top_reg().id().0;
2477        }
2478    }
2479
2480    extern "C" fn cb_intrinsic_class<A>(ctxt: *mut c_void, intrinsic: u32) -> BNIntrinsicClass
2481    where
2482        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2483    {
2484        let custom_arch = unsafe { &*(ctxt as *mut A) };
2485        custom_arch.intrinsic_class(IntrinsicId(intrinsic))
2486    }
2487
2488    extern "C" fn cb_intrinsic_name<A>(ctxt: *mut c_void, intrinsic: u32) -> *mut c_char
2489    where
2490        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2491    {
2492        let custom_arch = unsafe { &*(ctxt as *mut A) };
2493        match custom_arch.intrinsic_from_id(IntrinsicId(intrinsic)) {
2494            Some(intrinsic) => BnString::into_raw(BnString::new(intrinsic.name())),
2495            None => BnString::into_raw(BnString::new("invalid_intrinsic")),
2496        }
2497    }
2498
2499    extern "C" fn cb_intrinsics<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
2500    where
2501        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2502    {
2503        let custom_arch = unsafe { &*(ctxt as *mut A) };
2504        let mut intrinsics: Box<[_]> = custom_arch.intrinsics().iter().map(|i| i.id().0).collect();
2505
2506        // SAFETY: Passed in to be written
2507        unsafe { *count = intrinsics.len() };
2508        let intrinsics_ptr = intrinsics.as_mut_ptr();
2509        std::mem::forget(intrinsics);
2510        intrinsics_ptr
2511    }
2512
2513    extern "C" fn cb_intrinsic_inputs<A>(
2514        ctxt: *mut c_void,
2515        intrinsic: u32,
2516        count: *mut usize,
2517    ) -> *mut BNNameAndType
2518    where
2519        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2520    {
2521        let custom_arch = unsafe { &*(ctxt as *mut A) };
2522
2523        let Some(intrinsic) = custom_arch.intrinsic_from_id(IntrinsicId(intrinsic)) else {
2524            // SAFETY: Passed in to be written
2525            unsafe {
2526                *count = 0;
2527            }
2528            return std::ptr::null_mut();
2529        };
2530
2531        let inputs = intrinsic.inputs();
2532        // NOTE: The into_raw will leak and be freed later by `cb_free_name_and_types`.
2533        let raw_inputs: Box<[_]> = inputs.into_iter().map(NameAndType::into_raw).collect();
2534
2535        // SAFETY: Passed in to be written
2536        unsafe {
2537            *count = raw_inputs.len();
2538        }
2539
2540        if raw_inputs.is_empty() {
2541            std::ptr::null_mut()
2542        } else {
2543            // Core is responsible for calling back to `cb_free_name_and_types`.
2544            Box::leak(raw_inputs).as_mut_ptr()
2545        }
2546    }
2547
2548    extern "C" fn cb_free_name_and_types<A>(
2549        _ctxt: *mut c_void,
2550        nt: *mut BNNameAndType,
2551        count: usize,
2552    ) where
2553        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2554    {
2555        if nt.is_null() {
2556            return;
2557        }
2558
2559        // Reconstruct the box and drop.
2560        let nt_ptr = std::ptr::slice_from_raw_parts_mut(nt, count);
2561        // SAFETY: nt_ptr is a pointer to a Box.
2562        let boxed_name_and_types = unsafe { Box::from_raw(nt_ptr) };
2563        for nt in boxed_name_and_types {
2564            NameAndType::free_raw(nt);
2565        }
2566    }
2567
2568    extern "C" fn cb_intrinsic_outputs<A>(
2569        ctxt: *mut c_void,
2570        intrinsic: u32,
2571        count: *mut usize,
2572    ) -> *mut BNTypeWithConfidence
2573    where
2574        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2575    {
2576        let custom_arch = unsafe { &*(ctxt as *mut A) };
2577
2578        let Some(intrinsic) = custom_arch.intrinsic_from_id(IntrinsicId(intrinsic)) else {
2579            // SAFETY: Passed in to be written
2580            unsafe {
2581                *count = 0;
2582            }
2583            return std::ptr::null_mut();
2584        };
2585
2586        let outputs = intrinsic.outputs();
2587        let raw_outputs: Box<[BNTypeWithConfidence]> = outputs
2588            .into_iter()
2589            // Leaked to be freed later by `cb_free_type_list`.
2590            .map(Conf::<Ref<Type>>::into_raw)
2591            .collect();
2592
2593        // SAFETY: Passed in to be written
2594        unsafe {
2595            *count = raw_outputs.len();
2596        }
2597
2598        if raw_outputs.is_empty() {
2599            std::ptr::null_mut()
2600        } else {
2601            // Core is responsible for calling back to `cb_free_type_list`.
2602            Box::leak(raw_outputs).as_mut_ptr()
2603        }
2604    }
2605
2606    extern "C" fn cb_free_type_list<A>(
2607        ctxt: *mut c_void,
2608        tl: *mut BNTypeWithConfidence,
2609        count: usize,
2610    ) where
2611        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2612    {
2613        let _custom_arch = unsafe { &*(ctxt as *mut A) };
2614        if !tl.is_null() {
2615            let boxed_types =
2616                unsafe { Box::from_raw(std::ptr::slice_from_raw_parts_mut(tl, count)) };
2617            for ty in boxed_types {
2618                Conf::<Ref<Type>>::free_raw(ty);
2619            }
2620        }
2621    }
2622
2623    extern "C" fn cb_can_assemble<A>(ctxt: *mut c_void) -> bool
2624    where
2625        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2626    {
2627        let custom_arch = unsafe { &*(ctxt as *mut A) };
2628        custom_arch.can_assemble()
2629    }
2630
2631    extern "C" fn cb_assemble<A>(
2632        ctxt: *mut c_void,
2633        code: *const c_char,
2634        addr: u64,
2635        buffer: *mut BNDataBuffer,
2636        errors: *mut *mut c_char,
2637    ) -> bool
2638    where
2639        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2640    {
2641        let custom_arch = unsafe { &*(ctxt as *mut A) };
2642        let code = raw_to_string(code).unwrap_or("".into());
2643        let mut buffer = DataBuffer::from_raw(buffer);
2644
2645        let result = match custom_arch.assemble(&code, addr) {
2646            Ok(result) => {
2647                buffer.set_data(&result);
2648                unsafe {
2649                    *errors = BnString::into_raw(BnString::new(""));
2650                }
2651                true
2652            }
2653            Err(result) => {
2654                unsafe {
2655                    *errors = BnString::into_raw(BnString::new(result));
2656                }
2657                false
2658            }
2659        };
2660
2661        // Caller owns the data buffer, don't free it
2662        std::mem::forget(buffer);
2663
2664        result
2665    }
2666
2667    extern "C" fn cb_is_never_branch_patch_available<A>(
2668        ctxt: *mut c_void,
2669        data: *const u8,
2670        addr: u64,
2671        len: usize,
2672    ) -> bool
2673    where
2674        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2675    {
2676        let custom_arch = unsafe { &*(ctxt as *mut A) };
2677        let data = unsafe { std::slice::from_raw_parts(data, len) };
2678        custom_arch.is_never_branch_patch_available(data, addr)
2679    }
2680
2681    extern "C" fn cb_is_always_branch_patch_available<A>(
2682        ctxt: *mut c_void,
2683        data: *const u8,
2684        addr: u64,
2685        len: usize,
2686    ) -> bool
2687    where
2688        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2689    {
2690        let custom_arch = unsafe { &*(ctxt as *mut A) };
2691        let data = unsafe { std::slice::from_raw_parts(data, len) };
2692        custom_arch.is_always_branch_patch_available(data, addr)
2693    }
2694
2695    extern "C" fn cb_is_invert_branch_patch_available<A>(
2696        ctxt: *mut c_void,
2697        data: *const u8,
2698        addr: u64,
2699        len: usize,
2700    ) -> bool
2701    where
2702        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2703    {
2704        let custom_arch = unsafe { &*(ctxt as *mut A) };
2705        let data = unsafe { std::slice::from_raw_parts(data, len) };
2706        custom_arch.is_invert_branch_patch_available(data, addr)
2707    }
2708
2709    extern "C" fn cb_is_skip_and_return_zero_patch_available<A>(
2710        ctxt: *mut c_void,
2711        data: *const u8,
2712        addr: u64,
2713        len: usize,
2714    ) -> bool
2715    where
2716        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2717    {
2718        let custom_arch = unsafe { &*(ctxt as *mut A) };
2719        let data = unsafe { std::slice::from_raw_parts(data, len) };
2720        custom_arch.is_skip_and_return_zero_patch_available(data, addr)
2721    }
2722
2723    extern "C" fn cb_is_skip_and_return_value_patch_available<A>(
2724        ctxt: *mut c_void,
2725        data: *const u8,
2726        addr: u64,
2727        len: usize,
2728    ) -> bool
2729    where
2730        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2731    {
2732        let custom_arch = unsafe { &*(ctxt as *mut A) };
2733        let data = unsafe { std::slice::from_raw_parts(data, len) };
2734        custom_arch.is_skip_and_return_value_patch_available(data, addr)
2735    }
2736
2737    extern "C" fn cb_convert_to_nop<A>(
2738        ctxt: *mut c_void,
2739        data: *mut u8,
2740        addr: u64,
2741        len: usize,
2742    ) -> bool
2743    where
2744        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2745    {
2746        let custom_arch = unsafe { &*(ctxt as *mut A) };
2747        let data = unsafe { std::slice::from_raw_parts_mut(data, len) };
2748        custom_arch.convert_to_nop(data, addr)
2749    }
2750
2751    extern "C" fn cb_always_branch<A>(
2752        ctxt: *mut c_void,
2753        data: *mut u8,
2754        addr: u64,
2755        len: usize,
2756    ) -> bool
2757    where
2758        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2759    {
2760        let custom_arch = unsafe { &*(ctxt as *mut A) };
2761        let data = unsafe { std::slice::from_raw_parts_mut(data, len) };
2762        custom_arch.always_branch(data, addr)
2763    }
2764
2765    extern "C" fn cb_invert_branch<A>(
2766        ctxt: *mut c_void,
2767        data: *mut u8,
2768        addr: u64,
2769        len: usize,
2770    ) -> bool
2771    where
2772        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2773    {
2774        let custom_arch = unsafe { &*(ctxt as *mut A) };
2775        let data = unsafe { std::slice::from_raw_parts_mut(data, len) };
2776        custom_arch.invert_branch(data, addr)
2777    }
2778
2779    extern "C" fn cb_skip_and_return_value<A>(
2780        ctxt: *mut c_void,
2781        data: *mut u8,
2782        addr: u64,
2783        len: usize,
2784        val: u64,
2785    ) -> bool
2786    where
2787        A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2788    {
2789        let custom_arch = unsafe { &*(ctxt as *mut A) };
2790        let data = unsafe { std::slice::from_raw_parts_mut(data, len) };
2791        custom_arch.skip_and_return_value(data, addr, val)
2792    }
2793
2794    let uninit_arch = ArchitectureBuilder {
2795        arch: MaybeUninit::zeroed(),
2796        func: Some(func),
2797    };
2798
2799    let raw = Box::into_raw(Box::new(uninit_arch));
2800    let mut custom_arch = BNCustomArchitecture {
2801        context: raw as *mut _,
2802        init: Some(cb_init::<A, F>),
2803        getEndianness: Some(cb_endianness::<A>),
2804        getAddressSize: Some(cb_address_size::<A>),
2805        getDefaultIntegerSize: Some(cb_default_integer_size::<A>),
2806        getInstructionAlignment: Some(cb_instruction_alignment::<A>),
2807        // TODO: Make getOpcodeDisplayLength optional.
2808        getMaxInstructionLength: Some(cb_max_instr_len::<A>),
2809        // TODO: Make getOpcodeDisplayLength optional.
2810        getOpcodeDisplayLength: Some(cb_opcode_display_len::<A>),
2811        getAssociatedArchitectureByAddress: Some(cb_associated_arch_by_addr::<A>),
2812        getInstructionInfo: Some(cb_instruction_info::<A>),
2813        getInstructionText: Some(cb_get_instruction_text::<A>),
2814        getInstructionTextWithContext: Some(cb_get_instruction_text_with_context::<A>),
2815        freeInstructionText: Some(cb_free_instruction_text),
2816        getInstructionLowLevelIL: Some(cb_instruction_llil::<A>),
2817        analyzeBasicBlocks: Some(cb_analyze_basic_blocks::<A>),
2818        liftFunction: Some(cb_lift_function::<A>),
2819        freeFunctionArchContext: None,
2820
2821        getRegisterName: Some(cb_reg_name::<A>),
2822        getFlagName: Some(cb_flag_name::<A>),
2823        getFlagWriteTypeName: Some(cb_flag_write_name::<A>),
2824        getSemanticFlagClassName: Some(cb_semantic_flag_class_name::<A>),
2825        getSemanticFlagGroupName: Some(cb_semantic_flag_group_name::<A>),
2826
2827        getFullWidthRegisters: Some(cb_registers_full_width::<A>),
2828        getAllRegisters: Some(cb_registers_all::<A>),
2829        getAllFlags: Some(cb_flags::<A>),
2830        getAllFlagWriteTypes: Some(cb_flag_write_types::<A>),
2831        getAllSemanticFlagClasses: Some(cb_semantic_flag_classes::<A>),
2832        getAllSemanticFlagGroups: Some(cb_semantic_flag_groups::<A>),
2833
2834        getFlagRole: Some(cb_flag_role::<A>),
2835        getFlagsRequiredForFlagCondition: Some(cb_flags_required_for_flag_cond::<A>),
2836
2837        getFlagsRequiredForSemanticFlagGroup: Some(cb_flags_required_for_semantic_flag_group::<A>),
2838        getFlagConditionsForSemanticFlagGroup: Some(
2839            cb_flag_conditions_for_semantic_flag_group::<A>,
2840        ),
2841        freeFlagConditionsForSemanticFlagGroup: Some(
2842            cb_free_flag_conditions_for_semantic_flag_group::<A>,
2843        ),
2844
2845        getFlagsWrittenByFlagWriteType: Some(cb_flags_written_by_write_type::<A>),
2846        getSemanticClassForFlagWriteType: Some(cb_semantic_class_for_flag_write_type::<A>),
2847
2848        getFlagWriteLowLevelIL: Some(cb_flag_write_llil::<A>),
2849        getFlagConditionLowLevelIL: Some(cb_flag_cond_llil::<A>),
2850        getSemanticFlagGroupLowLevelIL: Some(cb_flag_group_llil::<A>),
2851
2852        freeRegisterList: Some(cb_free_register_list),
2853        getRegisterInfo: Some(cb_register_info::<A>),
2854        getStackPointerRegister: Some(cb_stack_pointer::<A>),
2855        getLinkRegister: Some(cb_link_reg::<A>),
2856        getGlobalRegisters: Some(cb_registers_global::<A>),
2857        getSystemRegisters: Some(cb_registers_system::<A>),
2858
2859        getRegisterStackName: Some(cb_reg_stack_name::<A>),
2860        getAllRegisterStacks: Some(cb_reg_stacks::<A>),
2861        getRegisterStackInfo: Some(cb_reg_stack_info::<A>),
2862
2863        getIntrinsicClass: Some(cb_intrinsic_class::<A>),
2864        getIntrinsicName: Some(cb_intrinsic_name::<A>),
2865        getAllIntrinsics: Some(cb_intrinsics::<A>),
2866        getIntrinsicInputs: Some(cb_intrinsic_inputs::<A>),
2867        freeNameAndTypeList: Some(cb_free_name_and_types::<A>),
2868        getIntrinsicOutputs: Some(cb_intrinsic_outputs::<A>),
2869        freeTypeList: Some(cb_free_type_list::<A>),
2870
2871        canAssemble: Some(cb_can_assemble::<A>),
2872        assemble: Some(cb_assemble::<A>),
2873
2874        isNeverBranchPatchAvailable: Some(cb_is_never_branch_patch_available::<A>),
2875        isAlwaysBranchPatchAvailable: Some(cb_is_always_branch_patch_available::<A>),
2876        isInvertBranchPatchAvailable: Some(cb_is_invert_branch_patch_available::<A>),
2877        isSkipAndReturnZeroPatchAvailable: Some(cb_is_skip_and_return_zero_patch_available::<A>),
2878        isSkipAndReturnValuePatchAvailable: Some(cb_is_skip_and_return_value_patch_available::<A>),
2879
2880        convertToNop: Some(cb_convert_to_nop::<A>),
2881        alwaysBranch: Some(cb_always_branch::<A>),
2882        invertBranch: Some(cb_invert_branch::<A>),
2883        skipAndReturnValue: Some(cb_skip_and_return_value::<A>),
2884        getLinearSweepInitialAlignment: Some(cb_linear_sweep_initial_alignment::<A>),
2885        getLinearSweepAnalysisCapabilities: Some(cb_linear_sweep_analysis_capabilities::<A>),
2886        supportsStandaloneInstructionDecoding: Some(
2887            cb_supports_standalone_instruction_decoding::<A>,
2888        ),
2889    };
2890
2891    customize(&mut custom_arch);
2892
2893    unsafe {
2894        match registration {
2895            ArchitectureRegistration::Hook(base) => {
2896                // Hook registration swaps the callbacks and returns the previous implementation.
2897                // Unlike BNRegisterArchitecture, it does not invoke the init callback.
2898                let previous = BNRegisterArchitectureHook(base.handle, &mut custom_arch);
2899                assert!(!previous.is_null());
2900                cb_init::<A, F>(raw.cast(), previous);
2901                // Finalization queries our callbacks to rebuild the register/flag caches, so the
2902                // Rust implementation must be fully initialized before this call.
2903                BNFinalizeArchitectureHook(base.handle);
2904            }
2905            ArchitectureRegistration::New(name) => {
2906                let name = name.to_cstr();
2907                let res = BNRegisterArchitecture(name.as_ptr(), &mut custom_arch);
2908                assert!(!res.is_null());
2909            }
2910        }
2911
2912        (*raw).arch.assume_init_mut()
2913    }
2914}
2915
2916pub fn register_architecture_with_function_context<A, F>(name: &str, func: F) -> &'static A
2917where
2918    A: 'static
2919        + ArchitectureWithFunctionContext<Handle = CustomArchitectureHandle<A>>
2920        + Send
2921        + Sync
2922        + Sized,
2923    F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
2924{
2925    unsafe extern "C" fn cb_free_function_arch_context_typed<A>(
2926        _ctxt: *mut c_void,
2927        context: *mut c_void,
2928    ) where
2929        A: 'static
2930            + ArchitectureWithFunctionContext<Handle = CustomArchitectureHandle<A>>
2931            + Send
2932            + Sync,
2933    {
2934        if context.is_null() {
2935            return;
2936        }
2937        // The context was allocated via Box::into_raw in set_function_arch_context,
2938        // so we reconstruct the Box here and let it drop.
2939        let _ = unsafe { Box::from_raw(context as *mut A::FunctionArchContext) };
2940    }
2941
2942    unsafe extern "C" fn cb_get_instruction_text_with_context_typed<A>(
2943        ctxt: *mut c_void,
2944        data: *const u8,
2945        addr: u64,
2946        len: *mut usize,
2947        context: *mut c_void,
2948        result: *mut *mut BNInstructionTextToken,
2949        count: *mut usize,
2950    ) -> bool
2951    where
2952        A: 'static
2953            + ArchitectureWithFunctionContext<Handle = CustomArchitectureHandle<A>>
2954            + Send
2955            + Sync,
2956    {
2957        let custom_arch = unsafe { &*(ctxt as *mut A) };
2958        let data = unsafe { std::slice::from_raw_parts(data, *len) };
2959        let result = unsafe { &mut *result };
2960        let typed_context: Option<&A::FunctionArchContext> = if context.is_null() {
2961            None
2962        } else {
2963            Some(unsafe { &*(context as *const A::FunctionArchContext) })
2964        };
2965
2966        let Some((res_size, res_tokens)) =
2967            custom_arch.instruction_text_with_typed_context(data, addr, typed_context)
2968        else {
2969            return false;
2970        };
2971
2972        let res_tokens: Box<[BNInstructionTextToken]> = res_tokens
2973            .into_iter()
2974            .map(InstructionTextToken::into_raw)
2975            .collect();
2976        unsafe {
2977            let res_tokens = Box::leak(res_tokens);
2978            *result = res_tokens.as_mut_ptr();
2979            *count = res_tokens.len();
2980            *len = res_size;
2981        }
2982        true
2983    }
2984
2985    register_architecture_impl(ArchitectureRegistration::New(name), func, |custom_arch| {
2986        custom_arch.freeFunctionArchContext = Some(cb_free_function_arch_context_typed::<A>);
2987        custom_arch.getInstructionTextWithContext =
2988            Some(cb_get_instruction_text_with_context_typed::<A>);
2989    })
2990}
2991
2992#[derive(Debug)]
2993pub struct CustomArchitectureHandle<A>
2994where
2995    A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2996{
2997    handle: *mut A,
2998}
2999
3000unsafe impl<A> Send for CustomArchitectureHandle<A> where
3001    A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync
3002{
3003}
3004
3005unsafe impl<A> Sync for CustomArchitectureHandle<A> where
3006    A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync
3007{
3008}
3009
3010impl<A> Clone for CustomArchitectureHandle<A>
3011where
3012    A: 'static + Architecture<Handle = Self> + Send + Sync,
3013{
3014    fn clone(&self) -> Self {
3015        *self
3016    }
3017}
3018
3019impl<A> Copy for CustomArchitectureHandle<A> where
3020    A: 'static + Architecture<Handle = Self> + Send + Sync
3021{
3022}
3023
3024impl<A> Borrow<A> for CustomArchitectureHandle<A>
3025where
3026    A: 'static + Architecture<Handle = Self> + Send + Sync,
3027{
3028    fn borrow(&self) -> &A {
3029        unsafe { &*self.handle }
3030    }
3031}