From 8f857a2fcbdfc7315cd09c0a4ac372b3ec92b538 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 9 Aug 2020 20:43:42 -0700 Subject: adjust public interface: public items should all be stable `OperandCode` (obviously) wildly varies depending on how i feel on a given week, so it's now hidden to avoid people depending on numerical values of its discriminants. `RegisterBank` got a similar treatment with a new `RegisterClass` struct that's suitable for public use. --- src/long_mode/mod.rs | 230 +++++++++++++++++++++++++++++++++------------- src/protected_mode/mod.rs | 193 +++++++++++++++++++++++++++----------- 2 files changed, 305 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 3d6dc2b..23213ec 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -9,14 +9,24 @@ use yaxpeax_arch::{AddressDiff, Decoder, LengthedInstruction}; #[cfg(feature="use-serde")] #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq, Serialize, Deserialize)] pub struct RegSpec { - pub num: u8, - pub bank: RegisterBank + num: u8, + bank: RegisterBank } #[cfg(not(feature="use-serde"))] #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)] pub struct RegSpec { - pub num: u8, - pub bank: RegisterBank + num: u8, + bank: RegisterBank +} + +impl RegSpec { + pub fn num(&self) -> u8 { + self.num + } + + pub fn class(&self) -> RegisterClass { + RegisterClass { kind: self.bank } + } } use core::hash::Hash; @@ -257,53 +267,39 @@ impl RegSpec { } #[inline] + pub fn r8b() -> RegSpec { + RegSpec { bank: RegisterBank::rB, num: 8 } + } + + #[inline] + pub fn zmm0() -> RegSpec { + RegSpec { bank: RegisterBank::Z, num: 0 } + } + + #[inline] + pub fn ymm0() -> RegSpec { + RegSpec { bank: RegisterBank::Y, num: 0 } + } + + #[inline] + pub fn xmm0() -> RegSpec { + RegSpec { bank: RegisterBank::X, num: 0 } + } + + #[inline] + pub fn st0() -> RegSpec { + RegSpec { bank: RegisterBank::ST, num: 0 } + } + + #[inline] + pub fn mm0() -> RegSpec { + RegSpec { bank: RegisterBank::MM, num: 0 } + } + + /// return the size of this register, in bytes + #[inline] pub fn width(&self) -> u8 { - match self.bank { - RegisterBank::Q => 8, - RegisterBank::D => 4, - RegisterBank::W => 2, - RegisterBank::B | - RegisterBank::rB => { - 1 - }, - RegisterBank::CR | - RegisterBank::DR => { - 8 - }, - RegisterBank::S => { - 2 - }, - RegisterBank::EIP => { - 4 - } - RegisterBank::RIP => { - 8 - } - RegisterBank::EFlags => { - 4 - } - RegisterBank::RFlags => { - 8 - } - RegisterBank::X => { - 16 - } - RegisterBank::Y => { - 32 - } - RegisterBank::Z => { - 64 - } - RegisterBank::ST => { - 10 - } - RegisterBank::MM => { - 8 - } - RegisterBank::K => { - 8 - } - } + self.class().width() } } @@ -439,6 +435,7 @@ impl Operand { } } } + pub fn is_memory(&self) -> bool { match self { Operand::DisplacementU32(_) | @@ -508,20 +505,125 @@ fn operand_size() { // assert_eq!(core::mem::size_of::(), 40); } +#[cfg(feature="use-serde")] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct RegisterClass { + kind: RegisterBank, +} + +#[cfg(not(feature="use-serde"))] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RegisterClass { + kind: RegisterBank, +} + +const REGISTER_CLASS_NAMES: &[&'static str] = &[ + "qword", + "BUG. PLEASE REPORT.", + "dword", + "BUG. PLEASE REPORT.", + "word", + "BUG. PLEASE REPORT.", + "byte", + "BUG. PLEASE REPORT.", + "rex-byte", + "BUG. PLEASE REPORT.", + "cr", + "BUG. PLEASE REPORT.", + "dr", + "BUG. PLEASE REPORT.", + "segment", + "xmm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "ymm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "zmm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "x87-stack", + "mmx", + "k", + "eip", + "rip", + "eflags", + "rflags", +]; + +impl RegisterClass { + pub fn name(&self) -> &'static str { + REGISTER_CLASS_NAMES[self.kind as usize] + } + + pub fn width(&self) -> u8 { + match self.kind { + RegisterBank::Q => 8, + RegisterBank::D => 4, + RegisterBank::W => 2, + RegisterBank::B | + RegisterBank::rB => { + 1 + }, + RegisterBank::CR | + RegisterBank::DR => { + 8 + }, + RegisterBank::S => { + 2 + }, + RegisterBank::EIP => { + 4 + } + RegisterBank::RIP => { + 8 + } + RegisterBank::EFlags => { + 4 + } + RegisterBank::RFlags => { + 8 + } + RegisterBank::X => { + 16 + } + RegisterBank::Y => { + 32 + } + RegisterBank::Z => { + 64 + } + RegisterBank::ST => { + 10 + } + RegisterBank::MM => { + 8 + } + RegisterBank::K => { + 8 + } + } + } +} + #[allow(non_camel_case_types)] #[cfg(feature="use-serde")] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)] -pub enum RegisterBank { +enum RegisterBank { Q = 0, D = 2, W = 4, B = 6, rB = 8, // Quadword, Dword, Word, Byte CR = 10, DR = 12, S = 14, EIP = 30, RIP = 31, EFlags = 32, RFlags = 33, // Control reg, Debug reg, Selector, ... X = 15, Y = 19, Z = 23, // XMM, YMM, ZMM ST = 27, MM = 28, // ST, MM regs (x87, mmx) K = 29, // AVX512 mask registers } + #[allow(non_camel_case_types)] #[cfg(not(feature="use-serde"))] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum RegisterBank { +enum RegisterBank { Q = 0, D = 2, W = 4, B = 6, rB = 8, // Quadword, Dword, Word, Byte CR = 10, DR = 12, S = 14, EIP = 30, RIP = 31, EFlags = 32, RFlags = 33, // Control reg, Debug reg, Selector, ... X = 15, Y = 19, Z = 23, // XMM, YMM, ZMM @@ -1565,7 +1667,7 @@ pub struct Instruction { operands: [OperandSpec; 4], imm: u64, disp: u64, - pub opcode: Opcode, + opcode: Opcode, } impl yaxpeax_arch::Instruction for Instruction { @@ -3079,25 +3181,25 @@ impl Default for Instruction { } impl Instruction { + pub fn opcode(&self) -> Opcode { + self.opcode + } + pub fn operand(&self, i: u8) -> Operand { assert!(i < 4); Operand::from_spec(self, self.operands[i as usize]) } pub fn operand_count(&self) -> u8 { - let mut i = 0; - for op in self.operands.iter() { - if let OperandSpec::Nothing = op { - return i; - } else { - i += 1; - } - } - return i; + self.operand_count } pub fn operand_present(&self, i: u8) -> bool { assert!(i < 4); + if i >= self.operand_count { + return false; + } + if let OperandSpec::Nothing = self.operands[i as usize] { false } else { @@ -3245,7 +3347,7 @@ impl Prefixes { #[inline] pub fn lock(&self) -> bool { self.bits & 0x4 == 4 } #[inline] - fn cs(&mut self) { self.segment = Segment::CS } + pub fn cs(&mut self) { self.segment = Segment::CS } #[inline] fn set_cs(&mut self) { self.segment = Segment::CS } #[inline] @@ -3520,7 +3622,7 @@ impl OperandCodeBuilder { // ---------------------------> read modr/m? #[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq)] -pub enum OperandCode { +enum OperandCode { Ivs = OperandCodeBuilder::new().special_case(25).bits(), I_3 = OperandCodeBuilder::new().special_case(27).bits(), Nothing = OperandCodeBuilder::new().special_case(28).bits(), diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 1517c7c..cb19a15 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -9,14 +9,24 @@ use yaxpeax_arch::{AddressDiff, Decoder, LengthedInstruction}; #[cfg(feature="use-serde")] #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq, Serialize, Deserialize)] pub struct RegSpec { - pub num: u8, - pub bank: RegisterBank + num: u8, + bank: RegisterBank } #[cfg(not(feature="use-serde"))] #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)] pub struct RegSpec { - pub num: u8, - pub bank: RegisterBank + num: u8, + bank: RegisterBank +} + +impl RegSpec { + pub fn num(&self) -> u8 { + self.num + } + + pub fn class(&self) -> RegisterClass { + RegisterClass { kind: self.bank } + } } use core::hash::Hash; @@ -236,43 +246,33 @@ impl RegSpec { } #[inline] + pub fn zmm0() -> RegSpec { + RegSpec { bank: RegisterBank::Z, num: 0 } + } + + #[inline] + pub fn ymm0() -> RegSpec { + RegSpec { bank: RegisterBank::Y, num: 0 } + } + + #[inline] + pub fn xmm0() -> RegSpec { + RegSpec { bank: RegisterBank::X, num: 0 } + } + + #[inline] + pub fn st0() -> RegSpec { + RegSpec { bank: RegisterBank::ST, num: 0 } + } + + #[inline] + pub fn mm0() -> RegSpec { + RegSpec { bank: RegisterBank::MM, num: 0 } + } + + #[inline] pub fn width(&self) -> u8 { - match self.bank { - RegisterBank::D => 4, - RegisterBank::W => 2, - RegisterBank::B => 1, - RegisterBank::CR | - RegisterBank::DR => { - 4 - }, - RegisterBank::S => { - 2 - }, - RegisterBank::EIP => { - 4 - } - RegisterBank::EFlags => { - 4 - } - RegisterBank::X => { - 16 - } - RegisterBank::Y => { - 32 - } - RegisterBank::Z => { - 64 - } - RegisterBank::ST => { - 10 - } - RegisterBank::MM => { - 8 - } - RegisterBank::K => { - 8 - } - } + self.class().width() } } @@ -463,10 +463,95 @@ fn operand_size() { // assert_eq!(core::mem::size_of::(), 40); } +#[cfg(feature="use-serde")] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct RegisterClass { + pub(self) kind: RegisterBank, +} + +#[cfg(not(feature="use-serde"))] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RegisterClass { + pub(self) kind: RegisterBank, +} + +const REGISTER_CLASS_NAMES: &[&'static str] = &[ + "dword", + "word", + "byte", + "cr", + "dr", + "segment", + "xmm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "ymm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "zmm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "x87-stack", + "mmx", + "k", + "eip", + "eflags", +]; + +impl RegisterClass { + /// return a human-friendly name for this register class + pub fn name(&self) -> &'static str { + REGISTER_CLASS_NAMES[self.kind as usize] + } + + /// return the size of this register class, in bytes + pub fn width(&self) -> u8 { + match self.kind { + RegisterBank::D => 4, + RegisterBank::W => 2, + RegisterBank::B => 1, + RegisterBank::CR | + RegisterBank::DR => { + 4 + }, + RegisterBank::S => { + 2 + }, + RegisterBank::EIP => { + 4 + } + RegisterBank::EFlags => { + 4 + } + RegisterBank::X => { + 16 + } + RegisterBank::Y => { + 32 + } + RegisterBank::Z => { + 64 + } + RegisterBank::ST => { + 10 + } + RegisterBank::MM => { + 8 + } + RegisterBank::K => { + 8 + } + } + } +} + #[allow(non_camel_case_types)] #[cfg(feature="use-serde")] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)] -pub enum RegisterBank { +enum RegisterBank { D = 0, W = 1, B = 2, // Dword, Word, Byte CR = 3, DR = 4, S = 5, EIP = 21, EFlags = 22, // Control reg, Debug reg, Selector, ... X = 6, Y = 10, Z = 14, // XMM, YMM, ZMM @@ -476,7 +561,7 @@ pub enum RegisterBank { #[allow(non_camel_case_types)] #[cfg(not(feature="use-serde"))] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum RegisterBank { +enum RegisterBank { D = 0, W = 1, B = 2, // Dword, Word, Byte CR = 3, DR = 4, S = 5, EIP = 21, EFlags = 22, // Control reg, Debug reg, Selector, ... X = 6, Y = 10, Z = 14, // XMM, YMM, ZMM @@ -1532,7 +1617,7 @@ pub struct Instruction { operands: [OperandSpec; 4], imm: u32, disp: u32, - pub opcode: Opcode, + opcode: Opcode, } impl yaxpeax_arch::Instruction for Instruction { @@ -3044,25 +3129,25 @@ impl Default for Instruction { } impl Instruction { + pub fn opcode(&self) -> Opcode { + self.opcode + } + pub fn operand(&self, i: u8) -> Operand { assert!(i < 4); Operand::from_spec(self, self.operands[i as usize]) } pub fn operand_count(&self) -> u8 { - let mut i = 0; - for op in self.operands.iter() { - if let OperandSpec::Nothing = op { - return i; - } else { - i += 1; - } - } - return i; + self.operand_count } pub fn operand_present(&self, i: u8) -> bool { assert!(i < 4); + if i >= self.operand_count { + return false; + } + if let OperandSpec::Nothing = self.operands[i as usize] { false } else { @@ -3212,7 +3297,7 @@ impl Prefixes { #[inline] pub fn lock(&self) -> bool { self.bits & 0x4 == 4 } #[inline] - fn cs(&mut self) { self.segment = Segment::CS } + pub fn cs(&mut self) { self.segment = Segment::CS } #[inline] fn set_cs(&mut self) { self.segment = Segment::CS } #[inline] @@ -3463,7 +3548,7 @@ impl OperandCodeBuilder { // ---------------------------> read modr/m? #[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq)] -pub enum OperandCode { +enum OperandCode { Ivs = OperandCodeBuilder::new().special_case(25).bits(), I_3 = OperandCodeBuilder::new().special_case(27).bits(), Nothing = OperandCodeBuilder::new().special_case(28).bits(), -- cgit v1.1