use std::fmt::{Display, Formatter, LowerHex, UpperHex, Write}; use std::ops::Range; use num_traits::{AsPrimitive, PrimInt}; pub use crate::iter::{disasm_iter, DisasmIterator}; pub mod formatter; mod generated; mod iter; pub use generated::*; pub mod prelude { pub use crate::formatter::FormattedIns; pub use crate::Argument; pub use crate::Field::*; pub use crate::Ins; pub use crate::Opcode::*; pub use crate::SimplifiedIns; pub use crate::{ Bit, BranchDest, CRBit, CRField, Offset, OpaqueU, Simm, Uimm, FPR, GPR, GQR, SPR, SR, }; } macro_rules! field_arg_no_display { ($name:ident, $typ:ident) => { #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct $name(pub $typ); impl std::convert::From<$name> for Argument { fn from(x: $name) -> Argument { Argument::$name(x) } } }; } macro_rules! field_arg { ($name:ident, $typ:ident) => { field_arg_no_display!($name, $typ); impl Display for $name { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } }; ($name:ident, $typ:ident, $format:literal) => { field_arg_no_display!($name, $typ); impl Display for $name { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, $format, self.0) } } }; ($name:ident, $typ:ident, $format:literal, $format_arg:expr) => { field_arg_no_display!($name, $typ); impl Display for $name { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, $format, $format_arg(self.0)) } } }; } #[inline(always)] fn bit(x: u32, idx: usize) -> bool { ((x >> (32 - idx - 1)) & 1) == 1 } #[inline(always)] fn bits(x: u32, range: Range) -> F where F: 'static + std::marker::Copy, u32: AsPrimitive, { let masked: u32 = (x >> (32 - range.end)) & ((1 << range.len()) - 1); masked.as_() } // https://stackoverflow.com/questions/44711012/how-do-i-format-a-signed-integer-to-a-sign-aware-hexadecimal-representation struct ReallySigned(N); impl LowerHex for ReallySigned { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let num = self.0.to_i32().unwrap(); let prefix = if f.alternate() { "0x" } else { "" }; let bare_hex = format!("{:x}", num.abs()); f.pad_integral(num >= 0, prefix, &bare_hex) } } impl UpperHex for ReallySigned { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let num = self.0.to_i32().unwrap(); let prefix = if f.alternate() { "0x" } else { "" }; let bare_hex = format!("{:X}", num.abs()); f.pad_integral(num >= 0, prefix, &bare_hex) } } // General-purpose register. field_arg!(GPR, u8, "r{}"); // Floating-point register (direct or paired-singles mode). field_arg!(FPR, u8, "f{}"); // Segment register. field_arg!(SR, u8); // Special-purpose register. field_arg_no_display!(SPR, u16); impl Display for SPR { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(match self.0 { 1 => "XER", 8 => "LR", 9 => "CTR", 18 => "DSISR", 19 => "DAR", 22 => "DEC", 25 => "SDR1", 26 => "SRR0", 27 => "SRR1", 272 => "SPRG0", 273 => "SPRG1", 274 => "SPRG2", 275 => "SPRG3", 282 => "EAR", 287 => "PVR", 528 => "IBAT0U", 529 => "IBAT0L", 530 => "IBAT1U", 531 => "IBAT1L", 532 => "IBAT2U", 533 => "IBAT2L", 534 => "IBAT3U", 535 => "IBAT3L", 536 => "DBAT0U", 537 => "DBAT0L", 538 => "DBAT1U", 539 => "DBAT1L", 540 => "DBAT2U", 541 => "DBAT2L", 542 => "DBAT3U", 543 => "DBAT3L", 912 => "GQR0", 913 => "GQR1", 914 => "GQR2", 915 => "GQR3", 916 => "GQR4", 917 => "GQR5", 918 => "GQR6", 919 => "GQR7", 920 => "HID2", 921 => "WPAR", 922 => "DMA_U", 923 => "DMA_L", 936 => "UMMCR0", 937 => "UPMC1", 938 => "UPMC2", 939 => "USIA", 940 => "UMMCR1", 941 => "UPMC3", 942 => "UPMC4", 943 => "USDA", 952 => "MMCR0", 953 => "PMC1", 954 => "PMC2", 955 => "SIA", 956 => "MMCR1", 957 => "PMC3", 958 => "PMC4", 959 => "SDA", 1008 => "HID0", 1009 => "HID1", 1010 => "IABR", 1013 => "DABR", 1017 => "L2CR", 1019 => "ICTC", 1020 => "THRM1", 1021 => "THRM2", 1022 => "THRM3", _ => return write!(f, "{}", self.0), }) } } // Condition register field. field_arg!(CRField, u8, "cr{}"); // Condition register bit (index + condition case). field_arg_no_display!(CRBit, u8); impl Display for CRBit { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let cr = self.0 >> 2; let cc = self.0 & 3; if cr != 0 { write!(f, "4*{}+", CRField(cr))?; } const CR_NAMES: [&str; 4] = ["lt", "gt", "eq", "so"]; f.write_str(CR_NAMES[cc as usize]) } } // Paired-single graphics quantization register field_arg!(GQR, u8, "qr{}"); // Unsigned immediate. field_arg!(Uimm, u16, "{:#x}"); // Signed immediate. field_arg!(Simm, i16, "{:#x}", ReallySigned); // Offset for indirect memory reference. field_arg!(Offset, i16, "{:#x}", ReallySigned); // Branch destination. field_arg!(BranchDest, i32, "{:#x}", ReallySigned); // Opaque zero or one argument. field_arg_no_display!(Bit, bool); impl Display for Bit { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_char(if self.0 { '1' } else { '0' }) } } // Unsigned opaque argument. field_arg!(OpaqueU, u32); #[derive(Debug, Clone)] pub enum Argument { GPR(GPR), FPR(FPR), SR(SR), SPR(SPR), CRField(CRField), CRBit(CRBit), GQR(GQR), Uimm(Uimm), Simm(Simm), Offset(Offset), BranchDest(BranchDest), Bit(Bit), OpaqueU(OpaqueU), } impl Display for Argument { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Argument::GPR(x) => x.fmt(f), Argument::FPR(x) => x.fmt(f), Argument::SR(x) => x.fmt(f), Argument::SPR(x) => x.fmt(f), Argument::CRField(x) => x.fmt(f), Argument::CRBit(x) => x.fmt(f), Argument::GQR(x) => x.fmt(f), Argument::Uimm(x) => x.fmt(f), Argument::Simm(x) => x.fmt(f), Argument::Offset(x) => x.fmt(f), Argument::BranchDest(x) => x.fmt(f), Argument::Bit(x) => x.fmt(f), Argument::OpaqueU(x) => x.fmt(f), } } } impl From for i64 { fn from(arg: Argument) -> Self { match arg { Argument::GPR(x) => x.0 as i64, Argument::FPR(x) => x.0 as i64, Argument::SR(x) => x.0 as i64, Argument::SPR(x) => x.0 as i64, Argument::CRField(x) => x.0 as i64, Argument::CRBit(x) => x.0 as i64, Argument::GQR(x) => x.0 as i64, Argument::Uimm(x) => x.0 as i64, Argument::Simm(x) => x.0 as i64, Argument::Offset(x) => x.0 as i64, Argument::BranchDest(x) => x.0 as i64, Argument::Bit(x) => x.0 as i64, Argument::OpaqueU(x) => x.0 as i64, } } } impl TryInto for &Field { type Error = (); fn try_into(self) -> Result { self.argument().ok_or(()) } } impl Opcode { /// Detects the opcode of a machine code instruction. pub fn detect(code: u32) -> Self { Self::_detect(code) // auto-generated } /// Prints the basic mnemonic of an opcode. pub fn mnemonic(self) -> &'static str { self._mnemonic() // auto-generated } } impl Default for Opcode { fn default() -> Self { Opcode::Illegal } } impl std::string::ToString for Opcode { fn to_string(&self) -> String { let mnemonic = self.mnemonic(); mnemonic.to_owned() } } /// A PowerPC 750CL instruction. #[derive(Default, Clone, Debug, Eq, PartialEq)] pub struct Ins { pub code: u32, pub addr: u32, pub op: Opcode, } impl Ins { const BLR: u32 = 0x4e800020; /// Constructs an instruction from the given machine code and address. pub fn new(code: u32, addr: u32) -> Self { Self { code, addr, op: Opcode::detect(code), } } /// Returns the simplified representation of an instruction. pub fn simplified(self) -> SimplifiedIns { self._simplified() // auto-generated } /// Gets the fields of an instruction. pub fn fields(&self) -> Vec { self._fields() // auto-generated } /// Gets the suffix of an instruction mnemonic. pub fn suffix(&self) -> String { self._suffix() // auto-generated } /// Gets the defs of an instruction. pub fn defs(&self) -> Vec { self._defs() // auto-generated } /// Gets the uses of an instruction. pub fn uses(&self) -> Vec { self._uses() // auto-generated } /// Gets the given bit from the machine code instruction. pub fn bit(&self, idx: usize) -> bool { bit(self.code, idx) } /// Gets the given range of btis from the machine code instruction. pub fn bits(&self, range: Range) -> u32 { bits(self.code, range) } pub fn branch_offset(&self) -> Option { match self.op { Opcode::B => Some(self.field_LI() as i32), Opcode::Bc => Some(self.field_BD() as i32), _ => None, } } pub fn branch_dest(&self) -> Option { self.branch_offset().and_then(|offset| { if self.field_AA() { Some(offset as u32) } else if offset < 0 { self.addr.checked_sub((-offset) as u32) } else { self.addr.checked_add(offset as u32) } }) } pub fn is_branch(&self) -> bool { matches!( self.op, Opcode::B | Opcode::Bc | Opcode::Bcctr | Opcode::Bclr ) } pub fn is_direct_branch(&self) -> bool { matches!(self.op, Opcode::B | Opcode::Bc) } pub fn is_unconditional_branch(&self) -> bool { match self.op { Opcode::B => true, Opcode::Bc | Opcode::Bcctr | Opcode::Bclr => { self.field_BO() == 20 && self.field_BI() == 0 } _ => false, } } pub fn is_conditional_branch(&self) -> bool { self.is_branch() && !self.is_unconditional_branch() } #[inline] pub fn is_blr(&self) -> bool { // self.op == Opcode::Bclr && self.is_unconditional_branch() && !self.field_LK() self.code == Ins::BLR } } /// A simplified PowerPC 750CL instruction. pub struct SimplifiedIns { pub ins: Ins, pub mnemonic: &'static str, pub suffix: String, pub args: Vec, } impl Display for SimplifiedIns { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}{} ", self.mnemonic, self.suffix)?; let mut writing_offset = false; for (i, argument) in self.args.iter().enumerate() { write!(f, "{}", argument)?; if let Argument::Offset(_) = argument { write!(f, "(")?; writing_offset = true; continue; } if writing_offset { write!(f, ")")?; writing_offset = false; } if i != self.args.len() - 1 { write!(f, ", ")?; } } Ok(()) } } impl SimplifiedIns { pub(crate) fn basic_form(ins: Ins) -> Self { Self { mnemonic: ins.op.mnemonic(), suffix: ins.suffix(), args: ins .fields() .iter() .flat_map(|field| field.argument()) .collect(), ins, } } }