From fd348552beb0b49fe631fd094749a44ffdef3418 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Tue, 20 Jan 2026 19:18:12 -0500 Subject: [PATCH 1/3] Rust: refactor Flag API * Add `UnusedFlagClass` and `UnusedFlagGroup` structs * Move the following methods from the `Architecture` trait into the various flag traits and pruned their list of super traits: * `Architecture::{flags, flag_from_id}` moved into `Flag` * `Architecture::{flag_write_types, flag_write_from_id}` moved into `FlagWrite` * `Architecture::{flag_classes, flag_class_from_id}` moved into `FlagClass` * `Architecture::{flag_groups, flag_group_from_id}` moved into `FlagGroup` --- arch/msp430/src/architecture.rs | 81 +----------- arch/msp430/src/flag.rs | 98 +++++--------- arch/riscv/src/lib.rs | 8 -- rust/src/architecture.rs | 209 +++--------------------------- rust/src/architecture/flag.rs | 219 +++++++++++++++++++++++++++----- 5 files changed, 245 insertions(+), 370 deletions(-) diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index 244c6b071b..86553223e7 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -1,11 +1,11 @@ -use crate::flag::{Flag, FlagClass, FlagGroup, FlagWrite}; +use crate::flag::{Flag, FlagWrite}; use crate::lift::lift_instruction; use crate::register::Register; use binaryninja::{ architecture::{ Architecture, CoreArchitecture, CustomArchitectureHandle, FlagCondition, InstructionInfo, - UnusedIntrinsic, UnusedRegisterStack, + UnusedFlagClass, UnusedFlagGroup, UnusedIntrinsic, UnusedRegisterStack, }, disassembly::{InstructionTextToken, InstructionTextTokenKind}, Endianness, @@ -16,9 +16,7 @@ use msp430_asm::{ single_operand::SingleOperand, two_operand::TwoOperand, }; -use binaryninja::architecture::{ - BranchKind, FlagClassId, FlagGroupId, FlagId, FlagWriteId, RegisterId, -}; +use binaryninja::architecture::{BranchKind, RegisterId}; use binaryninja::low_level_il::expression::ValueExpr; use binaryninja::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction}; @@ -47,8 +45,8 @@ impl Architecture for Msp430 { type RegisterInfo = Register; type Flag = Flag; type FlagWrite = FlagWrite; - type FlagClass = FlagClass; - type FlagGroup = FlagGroup; + type FlagClass = UnusedFlagClass; + type FlagGroup = UnusedFlagGroup; type Intrinsic = UnusedIntrinsic; fn endianness(&self) -> Endianness { @@ -71,14 +69,6 @@ impl Architecture for Msp430 { 6 } - fn opcode_display_len(&self) -> usize { - self.max_instr_len() - } - - fn associated_arch_by_addr(&self, _addr: u64) -> CoreArchitecture { - self.handle - } - fn instruction_info(&self, data: &[u8], addr: u64) -> Option { match msp430_asm::decode(data) { Ok(inst) => { @@ -272,43 +262,10 @@ impl Architecture for Msp430 { ] } - fn registers_global(&self) -> Vec { - Vec::new() - } - - fn registers_system(&self) -> Vec { - Vec::new() - } - - fn flags(&self) -> Vec { - vec![Flag::C, Flag::Z, Flag::N, Flag::V] - } - - fn flag_write_types(&self) -> Vec { - vec![ - FlagWrite::All, - FlagWrite::Nz, - FlagWrite::Nvz, - FlagWrite::Cnz, - ] - } - - fn flag_classes(&self) -> Vec { - Vec::new() - } - - fn flag_groups(&self) -> Vec { - Vec::new() - } - fn stack_pointer_reg(&self) -> Option { Some(Register::Sp) } - fn link_reg(&self) -> Option { - None - } - fn register_from_id(&self, id: RegisterId) -> Option { match id.try_into() { Ok(register) => Some(register), @@ -316,34 +273,6 @@ impl Architecture for Msp430 { } } - fn flag_from_id(&self, id: FlagId) -> Option { - match id.try_into() { - Ok(flag) => Some(flag), - Err(_) => { - tracing::error!("invalid flag id {}", id); - None - } - } - } - - fn flag_write_from_id(&self, id: FlagWriteId) -> Option { - match id.try_into() { - Ok(flag_write) => Some(flag_write), - Err(_) => { - tracing::error!("invalid flag write id {}", id); - None - } - } - } - - fn flag_class_from_id(&self, _: FlagClassId) -> Option { - None - } - - fn flag_group_from_id(&self, _: FlagGroupId) -> Option { - None - } - fn handle(&self) -> Self::Handle { self.custom_handle } diff --git a/arch/msp430/src/flag.rs b/arch/msp430/src/flag.rs index 698f3b199b..62248402a7 100644 --- a/arch/msp430/src/flag.rs +++ b/arch/msp430/src/flag.rs @@ -1,8 +1,7 @@ use binaryninja::architecture; -use binaryninja::architecture::{FlagClassId, FlagGroupId, FlagId, FlagRole, FlagWriteId}; +use binaryninja::architecture::{CoreArchitecture, FlagId, FlagRole, FlagWriteId, UnusedFlagClass}; use std::borrow::Cow; -use std::collections::HashMap; // NOTE: GIE, CPUOFF, OSCOFF, SG0, and SG1 not implemented as it's not clear how they would be used #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -14,7 +13,11 @@ pub enum Flag { } impl architecture::Flag for Flag { - type FlagClass = FlagClass; + type FlagClass = UnusedFlagClass; + + fn flags(_arch: &CoreArchitecture) -> Vec { + vec![Flag::C, Flag::Z, Flag::N, Flag::V] + } fn name(&self) -> Cow<'_, str> { match self { @@ -43,58 +46,18 @@ impl architecture::Flag for Flag { } .into() } -} -impl TryFrom for Flag { - type Error = (); - fn try_from(flag: FlagId) -> Result { - match flag.0 { - 0 => Ok(Self::C), - 1 => Ok(Self::Z), - 2 => Ok(Self::N), - 8 => Ok(Self::V), - _ => Err(()), + fn from_id(_arch: &CoreArchitecture, id: FlagId) -> Option { + match id.0 { + 0 => Some(Self::C), + 1 => Some(Self::Z), + 2 => Some(Self::N), + 8 => Some(Self::V), + _ => None, } } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct FlagClass {} - -impl architecture::FlagClass for FlagClass { - fn name(&self) -> Cow<'_, str> { - unimplemented!() - } - - fn id(&self) -> FlagClassId { - unimplemented!() - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum FlagGroup {} - -impl architecture::FlagGroup for FlagGroup { - type FlagType = Flag; - type FlagClass = FlagClass; - - fn name(&self) -> Cow<'_, str> { - unimplemented!() - } - - fn id(&self) -> FlagGroupId { - unimplemented!() - } - - fn flags_required(&self) -> Vec { - unimplemented!() - } - - fn flag_conditions(&self) -> HashMap { - unimplemented!() - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum FlagWrite { All, @@ -105,7 +68,16 @@ pub enum FlagWrite { impl architecture::FlagWrite for FlagWrite { type FlagType = Flag; - type FlagClass = FlagClass; + type FlagClass = UnusedFlagClass; + + fn flag_write_types(_arch: &CoreArchitecture) -> Vec { + vec![ + FlagWrite::All, + FlagWrite::Nz, + FlagWrite::Nvz, + FlagWrite::Cnz, + ] + } fn name(&self) -> Cow<'_, str> { match self { @@ -130,6 +102,16 @@ impl architecture::FlagWrite for FlagWrite { .into() } + fn from_id(_arch: &CoreArchitecture, id: FlagWriteId) -> Option { + match id.0 { + 1 => Some(Self::All), + 2 => Some(Self::Nz), + 3 => Some(Self::Nvz), + 4 => Some(Self::Cnz), + _ => None, + } + } + fn flags_written(&self) -> Vec { match self { Self::All => vec![Flag::C, Flag::N, Flag::V, Flag::Z], @@ -139,17 +121,3 @@ impl architecture::FlagWrite for FlagWrite { } } } - -impl TryFrom for FlagWrite { - type Error = (); - - fn try_from(value: FlagWriteId) -> Result { - match value.0 { - 1 => Ok(Self::All), - 2 => Ok(Self::Nz), - 3 => Ok(Self::Nvz), - 4 => Ok(Self::Cnz), - _ => Err(()), - } - } -} diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 1f822524d6..a3d92d8f1b 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -678,14 +678,6 @@ impl Architecture for RiscVArch { 4 } - fn opcode_display_len(&self) -> usize { - self.max_instr_len() - } - - fn associated_arch_by_addr(&self, _addr: u64) -> CoreArchitecture { - self.handle - } - fn instruction_info(&self, data: &[u8], addr: u64) -> Option { let (inst_len, op) = match D::decode(addr, data) { Ok(Instr::Rv16(op)) => (2, op), diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 6b5d44e543..11d48bd7ae 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -108,35 +108,24 @@ pub trait Architecture: 'static + Sized + AsRef { /// The [`Flag`] associated with this architecture. /// - /// If you do not override [`Architecture::flag_from_id`] and [`Architecture::flags`], you may - /// set this to [`UnusedFlag`]. + /// If the architecture does not use flags, you may set this to [`UnusedFlag`]. type Flag: Flag; /// The [`FlagWrite`] associated with this architecture. /// - /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that - /// this points to a custom [`FlagWrite`] with the following functions defined: - /// - /// - [`Architecture::flag_write_types`] - /// - [`Architecture::flag_write_from_id`] + /// If unused, this can be set to [`UnusedFlag`], but only if [`Self::Flag`] is unused as well. type FlagWrite: FlagWrite; /// The [`FlagClass`] associated with this architecture. /// - /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that - /// this points to a custom [`FlagClass`] with the following functions defined: - /// - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] + /// If unused, this can be set to either [`UnusedFlagClass`], or to [`UnusedFlag`] if + /// [`Self::Flag`] is also unused. type FlagClass: FlagClass; /// The [`FlagGroup`] associated with this architecture. /// - /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that - /// this points to a custom [`FlagGroup`] with the following functions defined: - /// - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] + /// If unused, this can be set to either [`UnusedFlagGroup`], or to [`UnusedFlag`] if + /// [`Self::Flag`] is also unused. type FlagGroup: FlagGroup; type Intrinsic: Intrinsic; @@ -336,119 +325,43 @@ pub trait Architecture: 'static + Sized + AsRef { } /// List of concrete flags for this architecture. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_types`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] fn flags(&self) -> Vec { - Vec::new() + Self::Flag::flags(self.as_ref()) } /// Get the [`Self::Flag`] associated with the given [`FlagId`]. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_write_types`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] - fn flag_from_id(&self, _id: FlagId) -> Option { - None + fn flag_from_id(&self, id: FlagId) -> Option { + Self::Flag::from_id(self.as_ref(), id) } /// List of concrete flag write types for this architecture. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] fn flag_write_types(&self) -> Vec { - Vec::new() + Self::FlagWrite::flag_write_types(self.as_ref()) } /// Get the [`Self::FlagWrite`] associated with the given [`FlagWriteId`]. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_types`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] - fn flag_write_from_id(&self, _id: FlagWriteId) -> Option { - None + fn flag_write_from_id(&self, id: FlagWriteId) -> Option { + Self::FlagWrite::from_id(self.as_ref(), id) } /// List of concrete flag classes for this architecture. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] fn flag_classes(&self) -> Vec { - Vec::new() + Self::FlagClass::flag_classes(self.as_ref()) } /// Get the [`Self::FlagClass`] associated with the given [`FlagClassId`]. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_groups`] - /// - [`Architecture::flag_group_from_id`] - fn flag_class_from_id(&self, _id: FlagClassId) -> Option { - None + fn flag_class_from_id(&self, id: FlagClassId) -> Option { + Self::FlagClass::from_id(self.as_ref(), id) } /// List of concrete flag groups for this architecture. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_group_from_id`] fn flag_groups(&self) -> Vec { - Vec::new() + Self::FlagGroup::flag_groups(self.as_ref()) } /// Get the [`Self::FlagGroup`] associated with the given [`FlagGroupId`]. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::flags`] - /// - [`Architecture::flag_from_id`] - /// - [`Architecture::flag_write_from_id`] - /// - [`Architecture::flag_classes`] - /// - [`Architecture::flag_class_from_id`] - /// - [`Architecture::flag_groups`] - fn flag_group_from_id(&self, _id: FlagGroupId) -> Option { - None + fn flag_group_from_id(&self, id: FlagGroupId) -> Option { + Self::FlagGroup::from_id(self.as_ref(), id) } /// List of concrete intrinsics for this architecture. @@ -782,7 +695,7 @@ impl Architecture for CoreArchitecture { let ret = std::slice::from_raw_parts(flags, count) .iter() .map(|&id| FlagId::from(id)) - .filter_map(|flag| CoreFlag::new(*self, flag)) + .filter_map(|flag| CoreFlag::from_id(self, flag)) .collect(); BNFreeRegisterList(flags); @@ -915,90 +828,6 @@ impl Architecture for CoreArchitecture { CoreRegisterStack::new(*self, id) } - fn flags(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let flags_raw = BNGetAllArchitectureFlags(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(flags_raw, count) - .iter() - .map(|&id| FlagId::from(id)) - .filter_map(|flag| CoreFlag::new(*self, flag)) - .collect(); - - BNFreeRegisterList(flags_raw); - - ret - } - } - - fn flag_from_id(&self, id: FlagId) -> Option { - CoreFlag::new(*self, id) - } - - fn flag_write_types(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let flag_writes_raw = BNGetAllArchitectureFlagWriteTypes(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(flag_writes_raw, count) - .iter() - .map(|&id| FlagWriteId::from(id)) - .filter_map(|flag_write| CoreFlagWrite::new(*self, flag_write)) - .collect(); - - BNFreeRegisterList(flag_writes_raw); - - ret - } - } - - fn flag_write_from_id(&self, id: FlagWriteId) -> Option { - CoreFlagWrite::new(*self, id) - } - - fn flag_classes(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let flag_classes_raw = BNGetAllArchitectureSemanticFlagClasses(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(flag_classes_raw, count) - .iter() - .map(|&id| FlagClassId::from(id)) - .filter_map(|flag_class| CoreFlagClass::new(*self, flag_class)) - .collect(); - - BNFreeRegisterList(flag_classes_raw); - - ret - } - } - - fn flag_class_from_id(&self, id: FlagClassId) -> Option { - CoreFlagClass::new(*self, id) - } - - fn flag_groups(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let flag_groups_raw = BNGetAllArchitectureSemanticFlagGroups(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(flag_groups_raw, count) - .iter() - .map(|&id| FlagGroupId::from(id)) - .filter_map(|flag_group| CoreFlagGroup::new(*self, flag_group)) - .collect(); - - BNFreeRegisterList(flag_groups_raw); - - ret - } - } - - fn flag_group_from_id(&self, id: FlagGroupId) -> Option { - CoreFlagGroup::new(*self, id) - } - fn intrinsics(&self) -> Vec { unsafe { let mut count: usize = 0; diff --git a/rust/src/architecture/flag.rs b/rust/src/architecture/flag.rs index 4cbd2dc1fb..2241a7ad22 100644 --- a/rust/src/architecture/flag.rs +++ b/rust/src/architecture/flag.rs @@ -15,9 +15,12 @@ new_id_type!(FlagWriteId, u32); new_id_type!(FlagClassId, u32); new_id_type!(FlagGroupId, u32); -pub trait Flag: Debug + Sized + Clone + Copy + Hash + Eq { +pub trait Flag: Copy { type FlagClass: FlagClass; + /// Must return a list of all possible flags. + fn flags(arch: &CoreArchitecture) -> Vec; + fn name(&self) -> Cow<'_, str>; fn role(&self, class: Option) -> FlagRole; @@ -25,12 +28,16 @@ pub trait Flag: Debug + Sized + Clone + Copy + Hash + Eq { /// /// *MUST* be in the range [0, 0x7fff_ffff] fn id(&self) -> FlagId; + fn from_id(arch: &CoreArchitecture, id: FlagId) -> Option; } -pub trait FlagWrite: Sized + Clone + Copy { +pub trait FlagWrite: Copy { type FlagType: Flag; type FlagClass: FlagClass; + /// Must return a list of all possible flag write types. + fn flag_write_types(arch: &CoreArchitecture) -> Vec; + fn name(&self) -> Cow<'_, str>; fn class(&self) -> Option; @@ -39,11 +46,15 @@ pub trait FlagWrite: Sized + Clone + Copy { /// *MUST NOT* be 0. /// *MUST* be in the range [1, 0x7fff_ffff] fn id(&self) -> FlagWriteId; + fn from_id(arch: &CoreArchitecture, id: FlagWriteId) -> Option; fn flags_written(&self) -> Vec; } -pub trait FlagClass: Sized + Clone + Copy + Hash + Eq { +pub trait FlagClass: Copy { + /// Must return a list of all possible flag classes. + fn flag_classes(arch: &CoreArchitecture) -> Vec; + fn name(&self) -> Cow<'_, str>; /// Unique identifier for this `FlagClass`. @@ -51,11 +62,15 @@ pub trait FlagClass: Sized + Clone + Copy + Hash + Eq { /// *MUST NOT* be 0. /// *MUST* be in the range [1, 0x7fff_ffff] fn id(&self) -> FlagClassId; + fn from_id(arch: &CoreArchitecture, id: FlagClassId) -> Option; } -pub trait FlagGroup: Debug + Sized + Clone + Copy { +pub trait FlagGroup: Copy { type FlagType: Flag; - type FlagClass: FlagClass; + type FlagClass: FlagClass + Hash + Eq; + + /// Must return a list of all possible flag groups. + fn flag_groups(arch: &CoreArchitecture) -> Vec; fn name(&self) -> Cow<'_, str>; @@ -63,6 +78,7 @@ pub trait FlagGroup: Debug + Sized + Clone + Copy { /// /// *MUST* be in the range [0, 0x7fff_ffff] fn id(&self) -> FlagGroupId; + fn from_id(arch: &CoreArchitecture, id: FlagGroupId) -> Option; /// Returns the list of flags that need to be resolved in order /// to take the clean flag resolution path -- at time of writing, @@ -97,12 +113,18 @@ pub struct UnusedFlag; impl Flag for UnusedFlag { type FlagClass = Self; + fn flags(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } fn name(&self) -> Cow<'_, str> { unreachable!() } fn role(&self, _class: Option) -> FlagRole { unreachable!() } + fn from_id(_arch: &CoreArchitecture, _id: FlagId) -> Option { + None + } fn id(&self) -> FlagId { unreachable!() } @@ -111,42 +133,109 @@ impl Flag for UnusedFlag { impl FlagWrite for UnusedFlag { type FlagType = Self; type FlagClass = Self; + fn flag_write_types(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } fn name(&self) -> Cow<'_, str> { unreachable!() } - fn class(&self) -> Option { + fn class(&self) -> Option { unreachable!() } fn id(&self) -> FlagWriteId { unreachable!() } + fn from_id(_arch: &CoreArchitecture, _id: FlagWriteId) -> Option { + None + } fn flags_written(&self) -> Vec { unreachable!() } } impl FlagClass for UnusedFlag { + fn flag_classes(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } fn name(&self) -> Cow<'_, str> { unreachable!() } fn id(&self) -> FlagClassId { unreachable!() } + fn from_id(_arch: &CoreArchitecture, _id: FlagClassId) -> Option { + None + } } impl FlagGroup for UnusedFlag { type FlagType = Self; type FlagClass = Self; + fn flag_groups(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } fn name(&self) -> Cow<'_, str> { unreachable!() } fn id(&self) -> FlagGroupId { unreachable!() } + fn from_id(_arch: &CoreArchitecture, _id: FlagGroupId) -> Option { + None + } fn flags_required(&self) -> Vec { unreachable!() } - fn flag_conditions(&self) -> HashMap { + fn flag_conditions(&self) -> HashMap { + unreachable!() + } +} + +/// Type for architectures that do not use flag classes, but may still use flags. Will panic if accessed as a flag class. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct UnusedFlagClass; + +impl FlagClass for UnusedFlagClass { + fn flag_classes(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } + fn name(&self) -> Cow<'_, str> { + unreachable!() + } + fn id(&self) -> FlagClassId { + unreachable!() + } + fn from_id(_arch: &CoreArchitecture, _id: FlagClassId) -> Option { + None + } +} + +/// Type for architectures that do not use flag groups, but may still use flags or flag classes. Will panic if accessed as a flag group. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct UnusedFlagGroup { + _flag: std::marker::PhantomData, + _class: std::marker::PhantomData, +} + +impl FlagGroup for UnusedFlagGroup { + type FlagType = F; + type FlagClass = C; + fn flag_groups(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } + fn name(&self) -> Cow<'_, str> { + unreachable!() + } + fn id(&self) -> FlagGroupId { + unreachable!() + } + fn from_id(_arch: &CoreArchitecture, _id: FlagGroupId) -> Option { + None + } + fn flags_required(&self) -> Vec { + unreachable!() + } + fn flag_conditions(&self) -> HashMap { unreachable!() } } @@ -158,11 +247,6 @@ pub struct CoreFlag { } impl CoreFlag { - pub fn new(arch: CoreArchitecture, id: FlagId) -> Option { - let flag = Self { arch, id }; - flag.is_valid().then_some(flag) - } - fn is_valid(&self) -> bool { // We check the name to see if the flag is actually valid. let name = unsafe { BNGetArchitectureFlagName(self.arch.handle, self.id.into()) }; @@ -179,6 +263,23 @@ impl CoreFlag { impl Flag for CoreFlag { type FlagClass = CoreFlagClass; + fn flags(arch: &CoreArchitecture) -> Vec { + let mut count: usize = 0; + unsafe { + let flags_raw = BNGetAllArchitectureFlags(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(flags_raw, count) + .iter() + .map(|&id| FlagId::from(id)) + .filter_map(|flag| Self::from_id(arch, flag)) + .collect(); + + BNFreeRegisterList(flags_raw); + + ret + } + } + fn name(&self) -> Cow<'_, str> { unsafe { let name = BNGetArchitectureFlagName(self.arch.handle, self.id.into()); @@ -208,6 +309,11 @@ impl Flag for CoreFlag { fn id(&self) -> FlagId { self.id } + + fn from_id(arch: &CoreArchitecture, id: FlagId) -> Option { + let flag_write = Self { arch: *arch, id }; + flag_write.is_valid().then_some(flag_write) + } } #[derive(Copy, Clone, Eq, PartialEq, Hash)] @@ -217,11 +323,6 @@ pub struct CoreFlagWrite { } impl CoreFlagWrite { - pub fn new(arch: CoreArchitecture, id: FlagWriteId) -> Option { - let flag_write = Self { arch, id }; - flag_write.is_valid().then_some(flag_write) - } - fn is_valid(&self) -> bool { // We check the name to see if the flag write is actually valid. let name = unsafe { BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into()) }; @@ -239,6 +340,23 @@ impl FlagWrite for CoreFlagWrite { type FlagType = CoreFlag; type FlagClass = CoreFlagClass; + fn flag_write_types(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let flag_writes_raw = BNGetAllArchitectureFlagWriteTypes(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(flag_writes_raw, count) + .iter() + .map(|&id| FlagWriteId::from(id)) + .filter_map(|flag_write| Self::from_id(arch, flag_write)) + .collect(); + + BNFreeRegisterList(flag_writes_raw); + + ret + } + } + fn name(&self) -> Cow<'_, str> { unsafe { let name = BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into()); @@ -262,7 +380,7 @@ impl FlagWrite for CoreFlagWrite { match class { 0 => None, - class_id => Some(CoreFlagClass::new(self.arch, class_id.into())?), + class_id => Some(CoreFlagClass::from_id(&self.arch, class_id.into())?), } } @@ -270,6 +388,11 @@ impl FlagWrite for CoreFlagWrite { self.id } + fn from_id(arch: &CoreArchitecture, id: FlagWriteId) -> Option { + let flag_write = Self { arch: *arch, id }; + flag_write.is_valid().then_some(flag_write) + } + fn flags_written(&self) -> Vec { let mut count: usize = 0; let regs: *mut u32 = unsafe { @@ -284,7 +407,7 @@ impl FlagWrite for CoreFlagWrite { std::slice::from_raw_parts(regs, count) .iter() .map(|id| FlagId::from(*id)) - .filter_map(|reg| CoreFlag::new(self.arch, reg)) + .filter_map(|reg| CoreFlag::from_id(&self.arch, reg)) .collect() }; @@ -303,11 +426,6 @@ pub struct CoreFlagClass { } impl CoreFlagClass { - pub fn new(arch: CoreArchitecture, id: FlagClassId) -> Option { - let flag = Self { arch, id }; - flag.is_valid().then_some(flag) - } - fn is_valid(&self) -> bool { // We check the name to see if the flag is actually valid. let name = @@ -323,6 +441,23 @@ impl CoreFlagClass { } impl FlagClass for CoreFlagClass { + fn flag_classes(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let flag_classes_raw = BNGetAllArchitectureSemanticFlagClasses(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(flag_classes_raw, count) + .iter() + .map(|&id| FlagClassId::from(id)) + .filter_map(|flag_class| Self::from_id(arch, flag_class)) + .collect(); + + BNFreeRegisterList(flag_classes_raw); + + ret + } + } + fn name(&self) -> Cow<'_, str> { unsafe { let name = BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into()); @@ -342,6 +477,11 @@ impl FlagClass for CoreFlagClass { fn id(&self) -> FlagClassId { self.id } + + fn from_id(arch: &CoreArchitecture, id: FlagClassId) -> Option { + let flag_write = Self { arch: *arch, id }; + flag_write.is_valid().then_some(flag_write) + } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -351,11 +491,6 @@ pub struct CoreFlagGroup { } impl CoreFlagGroup { - pub fn new(arch: CoreArchitecture, id: FlagGroupId) -> Option { - let flag_group = Self { arch, id }; - flag_group.is_valid().then_some(flag_group) - } - fn is_valid(&self) -> bool { // We check the name to see if the flag group is actually valid. let name = @@ -374,6 +509,23 @@ impl FlagGroup for CoreFlagGroup { type FlagType = CoreFlag; type FlagClass = CoreFlagClass; + fn flag_groups(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let flag_groups_raw = BNGetAllArchitectureSemanticFlagGroups(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(flag_groups_raw, count) + .iter() + .map(|&id| FlagGroupId::from(id)) + .filter_map(|flag_group| Self::from_id(arch, flag_group)) + .collect(); + + BNFreeRegisterList(flag_groups_raw); + + ret + } + } + fn name(&self) -> Cow<'_, str> { unsafe { let name = BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into()); @@ -394,6 +546,11 @@ impl FlagGroup for CoreFlagGroup { self.id } + fn from_id(arch: &CoreArchitecture, id: FlagGroupId) -> Option { + let flag_write = Self { arch: *arch, id }; + flag_write.is_valid().then_some(flag_write) + } + fn flags_required(&self) -> Vec { let mut count: usize = 0; let regs: *mut u32 = unsafe { @@ -408,7 +565,7 @@ impl FlagGroup for CoreFlagGroup { std::slice::from_raw_parts(regs, count) .iter() .map(|id| FlagId::from(*id)) - .filter_map(|reg| CoreFlag::new(self.arch, reg)) + .filter_map(|reg| CoreFlag::from_id(&self.arch, reg)) .collect() }; @@ -433,7 +590,7 @@ impl FlagGroup for CoreFlagGroup { .iter() .filter_map(|class_cond| { Some(( - CoreFlagClass::new(self.arch, class_cond.semanticClass.into())?, + CoreFlagClass::from_id(&self.arch, class_cond.semanticClass.into())?, class_cond.condition, )) }) From 76d518ccc73265e463137928d531e9d5ec7c1a33 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Sat, 31 Jan 2026 21:27:46 -0500 Subject: [PATCH 2/3] Rust: refactor Intrinsics API Move `Architecture::{intrinsics, intrinsic_from_id}` into the `Intrinsic` trait. --- arch/riscv/src/lib.rs | 214 ++++++++++++------------ rust/src/architecture.rs | 39 +---- rust/src/architecture/intrinsic.rs | 41 ++++- rust/src/high_level_il/instruction.rs | 10 +- rust/src/medium_level_il/instruction.rs | 14 +- 5 files changed, 156 insertions(+), 162 deletions(-) diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index a3d92d8f1b..9d058806bb 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -312,38 +312,6 @@ impl RiscVIntrinsic { Some(((id >> 20) & 0xfff, sz1, sz2, rm)) } - fn from_id(id: IntrinsicId) -> Option> { - match Self::parts_from_id(id) { - Some((0, _, _, _)) => Some(Intrinsic::Uret.into()), - Some((1, _, _, _)) => Some(Intrinsic::Sret.into()), - Some((2, _, _, _)) => Some(Intrinsic::Mret.into()), - Some((3, _, _, _)) => Some(Intrinsic::Wfi.into()), - Some((4, _, _, _)) => Some(Intrinsic::Csrrw.into()), - Some((5, _, _, _)) => Some(Intrinsic::Csrwr.into()), - Some((6, _, _, _)) => Some(Intrinsic::Csrrd.into()), - Some((7, _, _, _)) => Some(Intrinsic::Csrrs.into()), - Some((8, _, _, _)) => Some(Intrinsic::Csrrc.into()), - Some((9, size, _, rm)) => Some(Intrinsic::Fadd(size, rm).into()), - Some((10, size, _, rm)) => Some(Intrinsic::Fsub(size, rm).into()), - Some((11, size, _, rm)) => Some(Intrinsic::Fmul(size, rm).into()), - Some((12, size, _, rm)) => Some(Intrinsic::Fdiv(size, rm).into()), - Some((13, size, _, rm)) => Some(Intrinsic::Fsqrt(size, rm).into()), - Some((14, size, _, _)) => Some(Intrinsic::Fsgnj(size).into()), - Some((15, size, _, _)) => Some(Intrinsic::Fsgnjn(size).into()), - Some((16, size, _, _)) => Some(Intrinsic::Fsgnjx(size).into()), - Some((17, size, _, _)) => Some(Intrinsic::Fmin(size).into()), - Some((18, size, _, _)) => Some(Intrinsic::Fmax(size).into()), - Some((19, size, _, _)) => Some(Intrinsic::Fclass(size).into()), - Some((20, ssize, dsize, rm)) => Some(Intrinsic::FcvtFToF(ssize, dsize, rm).into()), - Some((21, isize, fsize, rm)) => Some(Intrinsic::FcvtIToF(isize, fsize, rm).into()), - Some((22, fsize, isize, rm)) => Some(Intrinsic::FcvtFToI(fsize, isize, rm).into()), - Some((23, usize, fsize, rm)) => Some(Intrinsic::FcvtUToF(usize, fsize, rm).into()), - Some((24, fsize, usize, rm)) => Some(Intrinsic::FcvtFToU(fsize, usize, rm).into()), - Some((25, _, _, _)) => Some(Intrinsic::Fence.into()), - _ => None, - } - } - fn int_size_suffix(size: u8) -> &'static str { match size { 4 => "_i32", @@ -391,6 +359,79 @@ impl From for RiscVIntrinsic { } impl architecture::Intrinsic for RiscVIntrinsic { + fn intrinsics(_: &CoreArchitecture) -> Vec { + let mut res = Vec::new(); + + res.extend_from_slice(&[ + Intrinsic::Uret, + Intrinsic::Sret, + Intrinsic::Mret, + Intrinsic::Wfi, + Intrinsic::Csrrw, + Intrinsic::Csrwr, + Intrinsic::Csrrd, + Intrinsic::Csrrs, + Intrinsic::Csrrc, + ]); + + if ::Float::present() { + let mut float_sizes = vec![4]; + if ::Float::width() >= 8 { + float_sizes.push(8); + } + if ::Float::width() >= 16 { + float_sizes.push(16); + } + let mut int_sizes = vec![4]; + if ::Int::width() >= 8 { + int_sizes.push(8); + } + + for fsize in &float_sizes { + res.extend_from_slice(&[ + Intrinsic::Fsgnj(*fsize), + Intrinsic::Fsgnjn(*fsize), + Intrinsic::Fsgnjx(*fsize), + Intrinsic::Fmin(*fsize), + Intrinsic::Fmax(*fsize), + Intrinsic::Fclass(*fsize), + ]); + for rm in RoundMode::all() { + if *rm != RoundMode::Dynamic { + res.extend_from_slice(&[ + Intrinsic::Fadd(*fsize, *rm), + Intrinsic::Fsub(*fsize, *rm), + Intrinsic::Fmul(*fsize, *rm), + Intrinsic::Fdiv(*fsize, *rm), + Intrinsic::Fsqrt(*fsize, *rm), + ]); + } + } + for dsize in &float_sizes { + if fsize != dsize { + for rm in RoundMode::all() { + if *rm != RoundMode::Dynamic { + res.push(Intrinsic::FcvtFToF(*fsize, *dsize, *rm)); + } + } + } + } + for isize in &int_sizes { + for rm in RoundMode::all() { + res.push(Intrinsic::FcvtFToU(*fsize, *isize, *rm)); + res.push(Intrinsic::FcvtUToF(*isize, *fsize, *rm)); + if *rm != RoundMode::Dynamic { + res.push(Intrinsic::FcvtFToI(*fsize, *isize, *rm)); + res.push(Intrinsic::FcvtIToF(*isize, *fsize, *rm)); + } + } + } + } + } + + res.iter().map(|i| (*i).into()).collect() + } + fn name(&self) -> Cow<'_, str> { match self.id { Intrinsic::Uret => "_uret".into(), @@ -518,6 +559,38 @@ impl architecture::Intrinsic for RiscVIntrinsic { } } + fn from_id(_arch: &CoreArchitecture, id: IntrinsicId) -> Option> { + match Self::parts_from_id(id) { + Some((0, _, _, _)) => Some(Intrinsic::Uret.into()), + Some((1, _, _, _)) => Some(Intrinsic::Sret.into()), + Some((2, _, _, _)) => Some(Intrinsic::Mret.into()), + Some((3, _, _, _)) => Some(Intrinsic::Wfi.into()), + Some((4, _, _, _)) => Some(Intrinsic::Csrrw.into()), + Some((5, _, _, _)) => Some(Intrinsic::Csrwr.into()), + Some((6, _, _, _)) => Some(Intrinsic::Csrrd.into()), + Some((7, _, _, _)) => Some(Intrinsic::Csrrs.into()), + Some((8, _, _, _)) => Some(Intrinsic::Csrrc.into()), + Some((9, size, _, rm)) => Some(Intrinsic::Fadd(size, rm).into()), + Some((10, size, _, rm)) => Some(Intrinsic::Fsub(size, rm).into()), + Some((11, size, _, rm)) => Some(Intrinsic::Fmul(size, rm).into()), + Some((12, size, _, rm)) => Some(Intrinsic::Fdiv(size, rm).into()), + Some((13, size, _, rm)) => Some(Intrinsic::Fsqrt(size, rm).into()), + Some((14, size, _, _)) => Some(Intrinsic::Fsgnj(size).into()), + Some((15, size, _, _)) => Some(Intrinsic::Fsgnjn(size).into()), + Some((16, size, _, _)) => Some(Intrinsic::Fsgnjx(size).into()), + Some((17, size, _, _)) => Some(Intrinsic::Fmin(size).into()), + Some((18, size, _, _)) => Some(Intrinsic::Fmax(size).into()), + Some((19, size, _, _)) => Some(Intrinsic::Fclass(size).into()), + Some((20, ssize, dsize, rm)) => Some(Intrinsic::FcvtFToF(ssize, dsize, rm).into()), + Some((21, isize, fsize, rm)) => Some(Intrinsic::FcvtIToF(isize, fsize, rm).into()), + Some((22, fsize, isize, rm)) => Some(Intrinsic::FcvtFToI(fsize, isize, rm).into()), + Some((23, usize, fsize, rm)) => Some(Intrinsic::FcvtUToF(usize, fsize, rm).into()), + Some((24, fsize, usize, rm)) => Some(Intrinsic::FcvtFToU(fsize, usize, rm).into()), + Some((25, _, _, _)) => Some(Intrinsic::Fence.into()), + _ => None, + } + } + fn inputs(&self) -> Vec { match self.id { Intrinsic::Uret | Intrinsic::Sret | Intrinsic::Mret | Intrinsic::Wfi => { @@ -1960,83 +2033,6 @@ impl Architecture for RiscVArch { } } - fn intrinsics(&self) -> Vec { - let mut res = Vec::new(); - - res.extend_from_slice(&[ - Intrinsic::Uret, - Intrinsic::Sret, - Intrinsic::Mret, - Intrinsic::Wfi, - Intrinsic::Csrrw, - Intrinsic::Csrwr, - Intrinsic::Csrrd, - Intrinsic::Csrrs, - Intrinsic::Csrrc, - ]); - - if ::Float::present() { - let mut float_sizes = vec![4]; - if ::Float::width() >= 8 { - float_sizes.push(8); - } - if ::Float::width() >= 16 { - float_sizes.push(16); - } - let mut int_sizes = vec![4]; - if ::Int::width() >= 8 { - int_sizes.push(8); - } - - for fsize in &float_sizes { - res.extend_from_slice(&[ - Intrinsic::Fsgnj(*fsize), - Intrinsic::Fsgnjn(*fsize), - Intrinsic::Fsgnjx(*fsize), - Intrinsic::Fmin(*fsize), - Intrinsic::Fmax(*fsize), - Intrinsic::Fclass(*fsize), - ]); - for rm in RoundMode::all() { - if *rm != RoundMode::Dynamic { - res.extend_from_slice(&[ - Intrinsic::Fadd(*fsize, *rm), - Intrinsic::Fsub(*fsize, *rm), - Intrinsic::Fmul(*fsize, *rm), - Intrinsic::Fdiv(*fsize, *rm), - Intrinsic::Fsqrt(*fsize, *rm), - ]); - } - } - for dsize in &float_sizes { - if fsize != dsize { - for rm in RoundMode::all() { - if *rm != RoundMode::Dynamic { - res.push(Intrinsic::FcvtFToF(*fsize, *dsize, *rm)); - } - } - } - } - for isize in &int_sizes { - for rm in RoundMode::all() { - res.push(Intrinsic::FcvtFToU(*fsize, *isize, *rm)); - res.push(Intrinsic::FcvtUToF(*isize, *fsize, *rm)); - if *rm != RoundMode::Dynamic { - res.push(Intrinsic::FcvtFToI(*fsize, *isize, *rm)); - res.push(Intrinsic::FcvtIToF(*isize, *fsize, *rm)); - } - } - } - } - } - - res.iter().map(|i| (*i).into()).collect() - } - - fn intrinsic_from_id(&self, id: IntrinsicId) -> Option { - RiscVIntrinsic::from_id(id) - } - fn can_assemble(&self) -> bool { true } diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 11d48bd7ae..9b71ff2789 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -365,12 +365,8 @@ pub trait Architecture: 'static + Sized + AsRef { } /// List of concrete intrinsics for this architecture. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::intrinsic_from_id`] fn intrinsics(&self) -> Vec { - Vec::new() + Self::Intrinsic::intrinsics(self.as_ref()) } fn intrinsic_class(&self, _id: IntrinsicId) -> BNIntrinsicClass { @@ -378,12 +374,8 @@ pub trait Architecture: 'static + Sized + AsRef { } /// Get the [`Self::Intrinsic`] associated with the given [`IntrinsicId`]. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::intrinsics`] - fn intrinsic_from_id(&self, _id: IntrinsicId) -> Option { - None + fn intrinsic_from_id(&self, id: IntrinsicId) -> Option { + Self::Intrinsic::from_id(self.as_ref(), id) } /// Let the UI display this patch option. @@ -796,14 +788,14 @@ impl Architecture for CoreArchitecture { fn stack_pointer_reg(&self) -> Option { match unsafe { BNGetArchitectureStackPointerRegister(self.handle) } { 0xffff_ffff => None, - reg => Some(CoreRegister::new(*self, reg.into())?), + reg => Some(CoreRegister::from_id(self, reg.into())?), } } fn link_reg(&self) -> Option { match unsafe { BNGetArchitectureLinkRegister(self.handle) } { 0xffff_ffff => None, - reg => Some(CoreRegister::new(*self, reg.into())?), + reg => Some(CoreRegister::from_id(self, reg.into())?), } } @@ -828,27 +820,6 @@ impl Architecture for CoreArchitecture { CoreRegisterStack::new(*self, id) } - fn intrinsics(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let intrinsics_raw = BNGetAllArchitectureIntrinsics(self.handle, &mut count); - - let intrinsics = std::slice::from_raw_parts_mut(intrinsics_raw, count) - .iter() - .map(|&id| IntrinsicId::from(id)) - .filter_map(|intrinsic| CoreIntrinsic::new(*self, intrinsic)) - .collect(); - - BNFreeRegisterList(intrinsics_raw); - - intrinsics - } - } - - fn intrinsic_from_id(&self, id: IntrinsicId) -> Option { - CoreIntrinsic::new(*self, id) - } - fn can_assemble(&self) -> bool { unsafe { BNCanArchitectureAssemble(self.handle) } } diff --git a/rust/src/architecture/intrinsic.rs b/rust/src/architecture/intrinsic.rs index a00b1e79e2..31a1738a61 100644 --- a/rust/src/architecture/intrinsic.rs +++ b/rust/src/architecture/intrinsic.rs @@ -3,7 +3,8 @@ use crate::confidence::Conf; use crate::rc::Ref; use crate::types::{NameAndType, Type}; use binaryninjacore_sys::{ - BNFreeNameAndTypeList, BNFreeOutputTypeList, BNFreeString, BNGetArchitectureIntrinsicClass, + BNFreeNameAndTypeList, BNFreeOutputTypeList, BNFreeRegisterList, BNFreeString, + BNGetAllArchitectureIntrinsics, BNGetArchitectureIntrinsicClass, BNGetArchitectureIntrinsicInputs, BNGetArchitectureIntrinsicName, BNGetArchitectureIntrinsicOutputs, BNIntrinsicClass, }; @@ -13,11 +14,14 @@ use std::fmt::{Debug, Formatter}; new_id_type!(IntrinsicId, u32); -pub trait Intrinsic: Debug + Sized + Clone + Copy { +pub trait Intrinsic: Copy { + fn intrinsics(arch: &CoreArchitecture) -> Vec; + fn name(&self) -> Cow<'_, str>; /// Unique identifier for this `Intrinsic`. fn id(&self) -> IntrinsicId; + fn from_id(arch: &CoreArchitecture, id: IntrinsicId) -> Option; /// The intrinsic class for this `Intrinsic`. fn class(&self) -> BNIntrinsicClass { @@ -37,12 +41,18 @@ pub trait Intrinsic: Debug + Sized + Clone + Copy { pub struct UnusedIntrinsic; impl Intrinsic for UnusedIntrinsic { + fn intrinsics(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } fn name(&self) -> Cow<'_, str> { unreachable!() } fn id(&self) -> IntrinsicId { unreachable!() } + fn from_id(_arch: &CoreArchitecture, _id: IntrinsicId) -> Option { + None + } fn inputs(&self) -> Vec { unreachable!() } @@ -58,11 +68,6 @@ pub struct CoreIntrinsic { } impl CoreIntrinsic { - pub fn new(arch: CoreArchitecture, id: IntrinsicId) -> Option { - let intrinsic = Self { arch, id }; - intrinsic.is_valid().then_some(intrinsic) - } - fn is_valid(&self) -> bool { // We check the name to see if the intrinsic is actually valid. let name = unsafe { BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into()) }; @@ -77,6 +82,23 @@ impl CoreIntrinsic { } impl Intrinsic for CoreIntrinsic { + fn intrinsics(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let intrinsics_raw = BNGetAllArchitectureIntrinsics(arch.handle, &mut count); + + let intrinsics = std::slice::from_raw_parts_mut(intrinsics_raw, count) + .iter() + .map(|&id| IntrinsicId::from(id)) + .filter_map(|intrinsic| CoreIntrinsic::from_id(arch, intrinsic)) + .collect(); + + BNFreeRegisterList(intrinsics_raw); + + intrinsics + } + } + fn name(&self) -> Cow<'_, str> { unsafe { let name = BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into()); @@ -98,6 +120,11 @@ impl Intrinsic for CoreIntrinsic { self.id } + fn from_id(arch: &CoreArchitecture, id: IntrinsicId) -> Option { + let intrinsic = Self { arch: *arch, id }; + intrinsic.is_valid().then_some(intrinsic) + } + fn class(&self) -> BNIntrinsicClass { unsafe { BNGetArchitectureIntrinsicClass(self.arch.handle, self.id.into()) } } diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs index 80be2a16fe..8777a85f06 100644 --- a/rust/src/high_level_il/instruction.rs +++ b/rust/src/high_level_il/instruction.rs @@ -4,7 +4,7 @@ use std::fmt::{Debug, Display, Formatter}; use super::operation::*; use super::{HighLevelILFunction, HighLevelILLiftedInstruction, HighLevelILLiftedInstructionKind}; -use crate::architecture::{CoreIntrinsic, IntrinsicId}; +use crate::architecture::{CoreIntrinsic, Intrinsic as _, IntrinsicId}; use crate::confidence::Conf; use crate::disassembly::DisassemblyTextLine; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; @@ -835,8 +835,8 @@ impl HighLevelILInstruction { cond_false: self.lift_operand(op.cond_false), }), Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { - intrinsic: CoreIntrinsic::new( - self.function.function().arch(), + intrinsic: CoreIntrinsic::from_id( + &self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Invalid intrinsic"), @@ -847,8 +847,8 @@ impl HighLevelILInstruction { .collect(), }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { - intrinsic: CoreIntrinsic::new( - self.function.function().arch(), + intrinsic: CoreIntrinsic::from_id( + &self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Invalid intrinsic"), diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index 17534b312a..185f66389b 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -1,7 +1,7 @@ use super::lift::*; use super::operation::*; use super::{MediumLevelILBlock, MediumLevelILFunction}; -use crate::architecture::{CoreIntrinsic, FlagId, IntrinsicId, RegisterId}; +use crate::architecture::{CoreIntrinsic, FlagId, Intrinsic as _, IntrinsicId, RegisterId}; use crate::basic_block::BasicBlock; use crate::confidence::Conf; use crate::disassembly::InstructionTextToken; @@ -937,8 +937,8 @@ impl MediumLevelILInstruction { Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { output: self.get_var_list(0), - intrinsic: CoreIntrinsic::new( - self.function.function().arch(), + intrinsic: CoreIntrinsic::from_id( + &self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), @@ -958,8 +958,8 @@ impl MediumLevelILInstruction { }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { output: self.get_ssa_var_list(0), - intrinsic: CoreIntrinsic::new( - self.function.function().arch(), + intrinsic: CoreIntrinsic::from_id( + &self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), @@ -971,8 +971,8 @@ impl MediumLevelILInstruction { }), MemoryIntrinsicSsa(op) => Lifted::MemoryIntrinsicSsa(LiftedMemoryIntrinsicSsa { output: self.lift_operand(op.output), - intrinsic: CoreIntrinsic::new( - self.function.function().arch(), + intrinsic: CoreIntrinsic::from_id( + &self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), From c376fde7059cabf9290bad213b7def802f6954b1 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Thu, 5 Feb 2026 16:07:18 -0500 Subject: [PATCH 3/3] Rust: refactor Register and RegisterStack API Move `Architecture::{register_stacks, register_stack_from_id}` into the `RegisterStack` trait. Plus, move the following into the `Register` trait: * `Architecture::registers_all` * `Architecture::registers_full_width` * `Architecture::registers_global` * `Architecture::registers_system` * `Architecture::stack_pointer_reg` * `Architecture::link_reg` --- arch/msp430/src/architecture.rs | 55 +--------- arch/msp430/src/register.rs | 32 +++++- arch/riscv/src/lib.rs | 100 +++++++++-------- rust/src/architecture.rs | 148 ++++--------------------- rust/src/architecture/register.rs | 167 ++++++++++++++++++++++++++--- rust/src/low_level_il/operation.rs | 4 +- 6 files changed, 250 insertions(+), 256 deletions(-) diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index 86553223e7..bee21a84ac 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -16,7 +16,7 @@ use msp430_asm::{ single_operand::SingleOperand, two_operand::TwoOperand, }; -use binaryninja::architecture::{BranchKind, RegisterId}; +use binaryninja::architecture::BranchKind; use binaryninja::low_level_il::expression::ValueExpr; use binaryninja::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction}; @@ -220,59 +220,6 @@ impl Architecture for Msp430 { None } - fn registers_all(&self) -> Vec { - vec![ - Register::Pc, - Register::Sp, - Register::Sr, - Register::Cg, - Register::R4, - Register::R5, - Register::R6, - Register::R7, - Register::R8, - Register::R9, - Register::R10, - Register::R11, - Register::R12, - Register::R13, - Register::R14, - Register::R15, - ] - } - - fn registers_full_width(&self) -> Vec { - vec![ - Register::Pc, - Register::Sp, - Register::Sr, - Register::Cg, - Register::R4, - Register::R5, - Register::R6, - Register::R7, - Register::R8, - Register::R9, - Register::R10, - Register::R11, - Register::R12, - Register::R13, - Register::R14, - Register::R15, - ] - } - - fn stack_pointer_reg(&self) -> Option { - Some(Register::Sp) - } - - fn register_from_id(&self, id: RegisterId) -> Option { - match id.try_into() { - Ok(register) => Some(register), - Err(_) => None, - } - } - fn handle(&self) -> Self::Handle { self.custom_handle } diff --git a/arch/msp430/src/register.rs b/arch/msp430/src/register.rs index 31339ea077..cf50a6d586 100644 --- a/arch/msp430/src/register.rs +++ b/arch/msp430/src/register.rs @@ -1,5 +1,4 @@ -use binaryninja::architecture; -use binaryninja::architecture::{ImplicitRegisterExtend, RegisterId}; +use binaryninja::architecture::{self, CoreArchitecture, ImplicitRegisterExtend, RegisterId}; use binaryninja::low_level_il::LowLevelILRegisterKind; use std::borrow::Cow; @@ -112,6 +111,35 @@ impl architecture::Register for Register { } .into() } + + fn from_id(_arch: &CoreArchitecture, id: RegisterId) -> Option { + id.try_into().ok() + } + + fn registers_all(_: &CoreArchitecture) -> Vec { + vec![ + Register::Pc, + Register::Sp, + Register::Sr, + Register::Cg, + Register::R4, + Register::R5, + Register::R6, + Register::R7, + Register::R8, + Register::R9, + Register::R10, + Register::R11, + Register::R12, + Register::R13, + Register::R14, + Register::R15, + ] + } + + fn stack_pointer_reg(_: &CoreArchitecture) -> Option { + Some(Register::Sp) + } } impl architecture::RegisterInfo for Register { diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 9d058806bb..26fd16fc8b 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -200,6 +200,54 @@ impl architecture::Register for Register { fn id(&self) -> RegisterId { self.id } + + fn from_id(_arch: &CoreArchitecture, id: RegisterId) -> Option { + let mut reg_count = ::int_reg_count(); + + if ::Float::present() { + reg_count += 32; + } + + if id.0 > reg_count { + None + } else { + Some(Register::new(id)) + } + } + + fn registers_all(_: &CoreArchitecture) -> Vec { + let mut reg_count = ::int_reg_count(); + + if ::Float::present() { + reg_count += 32; + } + + let mut res = Vec::with_capacity(reg_count as usize); + + for i in 0..reg_count { + res.push(Register::new(RegisterId(i))); + } + + res + } + + fn registers_global(_: &CoreArchitecture) -> Vec { + let mut regs = Vec::with_capacity(2); + + for i in &[3, 4] { + regs.push(Register::new(RegisterId(*i))); + } + + regs + } + + fn stack_pointer_reg(_: &CoreArchitecture) -> Option { + Some(Register::new(RegisterId(2))) + } + + fn link_reg(_: &CoreArchitecture) -> Option { + Some(Register::new(RegisterId(1))) + } } impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a> for Register { @@ -1981,58 +2029,6 @@ impl Architecture for RiscVArch { Some((inst_len as usize, true)) } - fn registers_all(&self) -> Vec { - let mut reg_count = ::int_reg_count(); - - if ::Float::present() { - reg_count += 32; - } - - let mut res = Vec::with_capacity(reg_count as usize); - - for i in 0..reg_count { - res.push(Register::new(RegisterId(i))); - } - - res - } - - fn registers_full_width(&self) -> Vec { - self.registers_all() - } - - fn registers_global(&self) -> Vec { - let mut regs = Vec::with_capacity(2); - - for i in &[3, 4] { - regs.push(Register::new(RegisterId(*i))); - } - - regs - } - - fn stack_pointer_reg(&self) -> Option { - Some(Register::new(RegisterId(2))) - } - - fn link_reg(&self) -> Option { - Some(Register::new(RegisterId(1))) - } - - fn register_from_id(&self, id: RegisterId) -> Option { - let mut reg_count = ::int_reg_count(); - - if ::Float::present() { - reg_count += 32; - } - - if id.0 > reg_count { - None - } else { - Some(Register::new(id)) - } - } - fn can_assemble(&self) -> bool { true } diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 9b71ff2789..fb280b5756 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -97,9 +97,6 @@ pub trait Architecture: 'static + Sized + AsRef { >; /// The [`RegisterStack`] associated with this architecture. - /// - /// If you do not override [`Architecture::register_stack_from_id`] and [`Architecture::register_stacks`], - /// you may set this to [`UnusedRegisterStack`]. type RegisterStack: RegisterStack< InfoType = Self::RegisterStackInfo, RegType = Self::Register, @@ -284,44 +281,42 @@ pub trait Architecture: 'static + Sized + AsRef { None } - fn registers_all(&self) -> Vec; + fn registers_all(&self) -> Vec { + Self::Register::registers_all(self.as_ref()) + } - fn register_from_id(&self, id: RegisterId) -> Option; + fn register_from_id(&self, id: RegisterId) -> Option { + Self::Register::from_id(self.as_ref(), id) + } - fn registers_full_width(&self) -> Vec; + fn registers_full_width(&self) -> Vec { + Self::Register::registers_full_width(self.as_ref()) + } - // TODO: Document the difference between global and system registers. fn registers_global(&self) -> Vec { - Vec::new() + Self::Register::registers_global(self.as_ref()) } - // TODO: Document the difference between global and system registers. fn registers_system(&self) -> Vec { - Vec::new() + Self::Register::registers_system(self.as_ref()) } - fn stack_pointer_reg(&self) -> Option; + fn stack_pointer_reg(&self) -> Option { + Self::Register::stack_pointer_reg(self.as_ref()) + } fn link_reg(&self) -> Option { - None + Self::Register::link_reg(self.as_ref()) } /// List of concrete register stacks for this architecture. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::register_stack_from_id`] fn register_stacks(&self) -> Vec { - Vec::new() + Self::RegisterStack::register_stacks(self.as_ref()) } /// Get the [`Self::RegisterStack`] associated with the given [`RegisterStackId`]. - /// - /// You **must** override the following functions as well: - /// - /// - [`Architecture::register_stacks`] - fn register_stack_from_id(&self, _id: RegisterStackId) -> Option { - None + fn register_stack_from_id(&self, id: RegisterStackId) -> Option { + Self::RegisterStack::from_id(self.as_ref(), id) } /// List of concrete flags for this architecture. @@ -713,113 +708,6 @@ impl Architecture for CoreArchitecture { None } - fn registers_all(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let registers_raw = BNGetAllArchitectureRegisters(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(registers_raw, count) - .iter() - .map(|&id| RegisterId::from(id)) - .filter_map(|reg| CoreRegister::new(*self, reg)) - .collect(); - - BNFreeRegisterList(registers_raw); - - ret - } - } - - fn register_from_id(&self, id: RegisterId) -> Option { - CoreRegister::new(*self, id) - } - - fn registers_full_width(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let registers_raw = BNGetFullWidthArchitectureRegisters(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(registers_raw, count) - .iter() - .map(|&id| RegisterId::from(id)) - .filter_map(|reg| CoreRegister::new(*self, reg)) - .collect(); - - BNFreeRegisterList(registers_raw); - - ret - } - } - - fn registers_global(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let registers_raw = BNGetArchitectureGlobalRegisters(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(registers_raw, count) - .iter() - .map(|&id| RegisterId::from(id)) - .filter_map(|reg| CoreRegister::new(*self, reg)) - .collect(); - - BNFreeRegisterList(registers_raw); - - ret - } - } - - fn registers_system(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let registers_raw = BNGetArchitectureSystemRegisters(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(registers_raw, count) - .iter() - .map(|&id| RegisterId::from(id)) - .filter_map(|reg| CoreRegister::new(*self, reg)) - .collect(); - - BNFreeRegisterList(registers_raw); - - ret - } - } - - fn stack_pointer_reg(&self) -> Option { - match unsafe { BNGetArchitectureStackPointerRegister(self.handle) } { - 0xffff_ffff => None, - reg => Some(CoreRegister::from_id(self, reg.into())?), - } - } - - fn link_reg(&self) -> Option { - match unsafe { BNGetArchitectureLinkRegister(self.handle) } { - 0xffff_ffff => None, - reg => Some(CoreRegister::from_id(self, reg.into())?), - } - } - - fn register_stacks(&self) -> Vec { - unsafe { - let mut count: usize = 0; - let reg_stacks_raw = BNGetAllArchitectureRegisterStacks(self.handle, &mut count); - - let ret = std::slice::from_raw_parts(reg_stacks_raw, count) - .iter() - .map(|&id| RegisterStackId::from(id)) - .filter_map(|reg_stack| CoreRegisterStack::new(*self, reg_stack)) - .collect(); - - BNFreeRegisterList(reg_stacks_raw); - - ret - } - } - - fn register_stack_from_id(&self, id: RegisterStackId) -> Option { - CoreRegisterStack::new(*self, id) - } - fn can_assemble(&self) -> bool { unsafe { BNCanArchitectureAssemble(self.handle) } } diff --git a/rust/src/architecture/register.rs b/rust/src/architecture/register.rs index 0f76084422..55b8c55d91 100644 --- a/rust/src/architecture/register.rs +++ b/rust/src/architecture/register.rs @@ -89,6 +89,31 @@ pub trait Register: Debug + Sized + Clone + Copy + Hash + Eq { /// /// NOTE: *MUST* be in the range [0, 0x7fff_ffff] fn id(&self) -> RegisterId; + fn from_id(arch: &CoreArchitecture, id: RegisterId) -> Option; + + fn registers_all(arch: &CoreArchitecture) -> Vec; + + /// By default returns the same as [`Self::registers_all`]. Provide an implementation if not + /// all registers are full-width. + fn registers_full_width(arch: &CoreArchitecture) -> Vec { + Self::registers_all(arch) + } + + // TODO: Document the difference between global and system registers. + fn registers_global(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } + + // TODO: Document the difference between global and system registers. + fn registers_system(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } + + fn stack_pointer_reg(arch: &CoreArchitecture) -> Option; + + fn link_reg(_arch: &CoreArchitecture) -> Option { + None + } } /// Information about a register stack. @@ -152,6 +177,9 @@ pub trait RegisterStack: Debug + Sized + Clone + Copy { type RegType: Register; type RegInfoType: RegisterInfo; + // Must return a list of all possible register stacks. + fn register_stacks(arch: &CoreArchitecture) -> Vec; + fn name(&self) -> Cow<'_, str>; fn info(&self) -> Self::InfoType; @@ -159,6 +187,7 @@ pub trait RegisterStack: Debug + Sized + Clone + Copy { /// /// *MUST* be in the range [0, 0x7fff_ffff] fn id(&self) -> RegisterStackId; + fn from_id(arch: &CoreArchitecture, id: RegisterStackId) -> Option; } /// Type for architectures that do not use register stacks. Will panic if accessed as a register stack. @@ -172,6 +201,9 @@ impl RegisterStack for UnusedRegisterStack { type RegType = R; type RegInfoType = R::InfoType; + fn register_stacks(_arch: &CoreArchitecture) -> Vec { + Vec::new() + } fn name(&self) -> Cow<'_, str> { unreachable!() } @@ -181,6 +213,9 @@ impl RegisterStack for UnusedRegisterStack { fn id(&self) -> RegisterStackId { unreachable!() } + fn from_id(_arch: &CoreArchitecture, _id: RegisterStackId) -> Option { + None + } } impl RegisterStackInfo for UnusedRegisterStack { @@ -217,8 +252,8 @@ impl RegisterInfo for CoreRegisterInfo { fn parent(&self) -> Option { if self.id != RegisterId::from(self.info.fullWidthRegister) { - Some(CoreRegister::new( - self.arch, + Some(CoreRegister::from_id( + &self.arch, RegisterId::from(self.info.fullWidthRegister), )?) } else { @@ -246,11 +281,6 @@ pub struct CoreRegister { } impl CoreRegister { - pub fn new(arch: CoreArchitecture, id: RegisterId) -> Option { - let register = Self { arch, id }; - register.is_valid().then_some(register) - } - fn is_valid(&self) -> bool { // We check the name to see if the register is actually valid. let name = unsafe { BNGetArchitectureRegisterName(self.arch.handle, self.id.into()) }; @@ -292,6 +322,93 @@ impl Register for CoreRegister { fn id(&self) -> RegisterId { self.id } + + fn from_id(arch: &CoreArchitecture, id: RegisterId) -> Option { + let register = Self { arch: *arch, id }; + register.is_valid().then_some(register) + } + + fn registers_all(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let registers_raw = BNGetAllArchitectureRegisters(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(registers_raw, count) + .iter() + .map(|&id| RegisterId::from(id)) + .filter_map(|reg| Self::from_id(arch, reg)) + .collect(); + + BNFreeRegisterList(registers_raw); + + ret + } + } + + fn registers_full_width(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let registers_raw = BNGetFullWidthArchitectureRegisters(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(registers_raw, count) + .iter() + .map(|&id| RegisterId::from(id)) + .filter_map(|reg| Self::from_id(arch, reg)) + .collect(); + + BNFreeRegisterList(registers_raw); + + ret + } + } + + fn registers_global(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let registers_raw = BNGetArchitectureGlobalRegisters(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(registers_raw, count) + .iter() + .map(|&id| RegisterId::from(id)) + .filter_map(|reg| Self::from_id(arch, reg)) + .collect(); + + BNFreeRegisterList(registers_raw); + + ret + } + } + + fn registers_system(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let registers_raw = BNGetArchitectureSystemRegisters(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(registers_raw, count) + .iter() + .map(|&id| RegisterId::from(id)) + .filter_map(|reg| Self::from_id(arch, reg)) + .collect(); + + BNFreeRegisterList(registers_raw); + + ret + } + } + + fn stack_pointer_reg(arch: &CoreArchitecture) -> Option { + match unsafe { BNGetArchitectureStackPointerRegister(arch.handle) } { + 0xffff_ffff => None, + reg => Some(Self::from_id(arch, reg.into())?), + } + } + + fn link_reg(arch: &CoreArchitecture) -> Option { + match unsafe { BNGetArchitectureLinkRegister(arch.handle) } { + 0xffff_ffff => None, + reg => Some(Self::from_id(arch, reg.into())?), + } + } } impl Debug for CoreRegister { @@ -315,7 +432,8 @@ unsafe impl CoreArrayProviderInner for CoreRegister { } unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::new(*context, RegisterId::from(*raw)).expect("Register list contains valid registers") + Self::from_id(context, RegisterId::from(*raw)) + .expect("Register list contains valid registers") } } @@ -339,7 +457,7 @@ impl RegisterStackInfo for CoreRegisterStackInfo { fn storage_regs(&self) -> (Self::RegType, usize) { ( - CoreRegister::new(self.arch, RegisterId::from(self.info.firstStorageReg)) + CoreRegister::from_id(&self.arch, RegisterId::from(self.info.firstStorageReg)) .expect("Storage register is valid"), self.info.storageCount as usize, ) @@ -350,7 +468,7 @@ impl RegisterStackInfo for CoreRegisterStackInfo { None } else { Some(( - CoreRegister::new(self.arch, RegisterId::from(self.info.firstTopRelativeReg)) + CoreRegister::from_id(&self.arch, RegisterId::from(self.info.firstTopRelativeReg)) .expect("Top relative register is valid"), self.info.topRelativeCount as usize, )) @@ -358,7 +476,7 @@ impl RegisterStackInfo for CoreRegisterStackInfo { } fn stack_top_reg(&self) -> Self::RegType { - CoreRegister::new(self.arch, RegisterId::from(self.info.stackTopReg)) + CoreRegister::from_id(&self.arch, RegisterId::from(self.info.stackTopReg)) .expect("Stack top register is valid") } } @@ -370,11 +488,6 @@ pub struct CoreRegisterStack { } impl CoreRegisterStack { - pub fn new(arch: CoreArchitecture, id: RegisterStackId) -> Option { - let register_stack = Self { arch, id }; - register_stack.is_valid().then_some(register_stack) - } - fn is_valid(&self) -> bool { // We check the name to see if the stack register is actually valid. let name = unsafe { BNGetArchitectureRegisterStackName(self.arch.handle, self.id.into()) }; @@ -393,6 +506,23 @@ impl RegisterStack for CoreRegisterStack { type RegType = CoreRegister; type RegInfoType = CoreRegisterInfo; + fn register_stacks(arch: &CoreArchitecture) -> Vec { + unsafe { + let mut count: usize = 0; + let reg_stacks_raw = BNGetAllArchitectureRegisterStacks(arch.handle, &mut count); + + let ret = std::slice::from_raw_parts(reg_stacks_raw, count) + .iter() + .map(|&id| RegisterStackId::from(id)) + .filter_map(|reg_stack| CoreRegisterStack::from_id(arch, reg_stack)) + .collect(); + + BNFreeRegisterList(reg_stacks_raw); + + ret + } + } + fn name(&self) -> Cow<'_, str> { unsafe { let name = BNGetArchitectureRegisterStackName(self.arch.handle, self.id.into()); @@ -418,4 +548,9 @@ impl RegisterStack for CoreRegisterStack { fn id(&self) -> RegisterStackId { self.id } + + fn from_id(arch: &CoreArchitecture, id: RegisterStackId) -> Option { + let register_stack = Self { arch: *arch, id }; + register_stack.is_valid().then_some(register_stack) + } } diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 8f94b74f36..0f93f30917 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -416,7 +416,7 @@ where let full_reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), full_raw_id) .expect("Bad register ID"); let partial_reg = - CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID"); + CoreRegister::from_id(&self.function.arch(), partial_raw_id).expect("Bad register ID"); LowLevelILSSARegisterKind::new_partial(full_reg_kind, version, partial_reg) } @@ -871,7 +871,7 @@ where let full_reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), full_raw_id) .expect("Bad register ID"); let partial_reg = - CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID"); + CoreRegister::from_id(&self.function.arch(), partial_raw_id).expect("Bad register ID"); LowLevelILSSARegisterKind::new_partial(full_reg_kind, version, partial_reg) } }