use crate::x86::arch_traits::{X64_ARCH_TRAITS, X86_ARCH_TRAITS};
use super::operand::{OperandSignature, RegGroup, RegType};
use super::types::TypeId;
pub struct ArchTraits {
pub sp_reg_id: u8,
pub fp_reg_id: u8,
pub link_reg_id: u8,
pub ip_reg_id: u8,
pub hw_stack_alignment: u8,
pub min_stack_offset: u32,
pub max_stack_offset: u32,
pub regs_signature: [OperandSignature; RegType::MaxValue as usize + 1],
pub reg_type_to_type_id: [TypeId; RegType::MaxValue as usize + 1],
pub type_id_to_reg_type: [RegType; 32],
}
pub const ARCH_X86: usize = if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
usize::BITS as usize
} else {
0
};
pub const ARCH_ARM: usize = if cfg!(any(target_arch = "aarch64", target_arch = "arm")) {
usize::BITS as usize
} else {
0
};
pub const ARCH_RISCV: usize = if cfg!(any(target_arch = "riscv64", target_arch = "riscv32")) {
usize::BITS as usize
} else {
0
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Arch {
Unknown = 0,
X86 = 1,
X64 = 2,
RISCV32 = 3,
RISCV64 = 4,
ARM = 5,
AArch64 = 6,
Thumb = 7,
MIPS32LE = 9,
MIPS64LE = 10,
ARMBE = 11,
AArch64BE = 12,
ThumbBE = 13,
MIPS32BE = 15,
MIPS64BE = 16,
Max,
}
impl Arch {
pub const HOST: Arch = {
if ARCH_X86 == 32 {
Arch::X86
} else if ARCH_X86 == 64 {
Arch::X64
} else if ARCH_RISCV == 32 {
Arch::RISCV32
} else if ARCH_RISCV == 64 {
Arch::RISCV64
} else if ARCH_ARM == 32 && cfg!(target_endian = "little") {
Arch::ARM
} else if ARCH_ARM == 32 && cfg!(target_endian = "big") {
Arch::ARMBE
} else if ARCH_ARM == 64 && cfg!(target_endian = "little") {
Arch::AArch64
} else if ARCH_ARM == 64 && cfg!(target_endian = "big") {
Arch::AArch64BE
} else {
Arch::Unknown
}
};
}
impl Default for Arch {
fn default() -> Self {
Self::HOST
}
}
const NO_ARCH_TRAITS: ArchTraits = ArchTraits {
fp_reg_id: 0xff,
sp_reg_id: 0xff,
link_reg_id: 0xff,
ip_reg_id: 0xff,
hw_stack_alignment: 0,
min_stack_offset: 0,
max_stack_offset: 0,
regs_signature: [OperandSignature::new(0); 32],
reg_type_to_type_id: [TypeId::Void; 32],
type_id_to_reg_type: [RegType::None; 32],
};
#[rustfmt::skip]
const ARCH_TRAITS: [ArchTraits; Arch::Max as usize] =[
NO_ARCH_TRAITS,
X86_ARCH_TRAITS,
X64_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
NO_ARCH_TRAITS,
];
impl ArchTraits {
pub const fn sp_reg_id(&self) -> u32 {
self.sp_reg_id as _
}
pub const fn fp_reg_id(&self) -> u32 {
self.fp_reg_id as _
}
pub const fn link_reg_id(&self) -> u32 {
self.link_reg_id as _
}
pub const fn ip_reg_id(&self) -> u32 {
self.ip_reg_id as _
}
pub const fn hw_stack_alignment(&self) -> u32 {
self.hw_stack_alignment as _
}
pub const fn has_link_reg(&self) -> bool {
self.link_reg_id != 0xff
}
pub const fn min_stack_offset(&self) -> u32 {
self.min_stack_offset
}
pub const fn max_stack_offset(&self) -> u32 {
self.max_stack_offset
}
pub const fn has_reg_type(&self, typ: RegType) -> bool {
(typ as u32) <= RegType::MaxValue as u32 && self.regs_signature[typ as usize].is_valid()
}
pub const fn reg_type_to_signature(&self, typ: RegType) -> OperandSignature {
self.regs_signature[typ as usize]
}
pub fn reg_type_to_group(&self, typ: RegType) -> RegGroup {
self.reg_type_to_signature(typ).reg_group()
}
pub fn reg_type_to_size(&self, typ: RegType) -> u32 {
self.reg_type_to_signature(typ).size()
}
pub const fn reg_type_to_type_id(&self, typ: RegType) -> TypeId {
self.reg_type_to_type_id[typ as usize]
}
pub const fn by_arch(arch: Arch) -> &'static Self {
&ARCH_TRAITS[arch as usize]
}
}