From 6248d3c5f7dd196acdfce5c0da1608fed81b43cd Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 9 Aug 2020 20:49:12 -0700 Subject: inaugural 0.1.0 release! add doc comments for public items, record changelog, and lets ship this!! --- CHANGELOG | 8 ++++++++ Cargo.toml | 2 +- src/long_mode/mod.rs | 44 +++++++++++++++++++++++++++++--------------- src/protected_mode/mod.rs | 39 +++++++++++++++++++++++++++------------ 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c846cdb..3fd659a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,14 @@ * support x86_32 `pusha`/`popa` * support x86_32 BCD instructions - for `aam`/`aad`, the undocumented `amx` and `adx` forms are used in all cases, including when the base is 10 +* begin some proper documentation for public items + +/!\ BREAKING CHANGES /!\ +* `RegisterBank` is no longer public. `RegisterClass` should be a suitable + replacement, accessible via `reg.class()`, with the register class name + available by `reg.class().name`, and size available by `reg.class().width()`. + `reg.width()` still works, and just forwards to `reg.class().width()`. +* the field `opcode` of `Instruction` is no longer public. it can now be accessed by `inst.opcode()`. ## 0.0.15 diff --git a/Cargo.toml b/Cargo.toml index 2d00142..889b54a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "yaxpeax-x86" -version = "0.0.15" +version = "0.1.0" authors = [ "iximeow " ] license = "0BSD" repository = "http://git.iximeow.net/yaxpeax-x86/" diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 23213ec..f328c72 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -19,16 +19,6 @@ pub struct RegSpec { bank: RegisterBank } -impl RegSpec { - pub fn num(&self) -> u8 { - self.num - } - - pub fn class(&self) -> RegisterClass { - RegisterClass { kind: self.bank } - } -} - use core::hash::Hash; use core::hash::Hasher; impl Hash for RegSpec { @@ -70,6 +60,16 @@ pub enum ConditionCode { #[allow(non_snake_case)] impl RegSpec { + pub fn num(&self) -> u8 { + self.num + } + + pub fn class(&self) -> RegisterClass { + RegisterClass { kind: self.bank } + } + + /// return a human-friendly name for this register. the returned name is the same as would be + /// used to render this register in an instruction. pub fn name(&self) -> &'static str { display::regspec_label(self) } @@ -465,6 +465,10 @@ impl Operand { } } + /// return the width of this operand, in bytes. register widths are determined by the + /// register's class. + /// + /// TODO: /!\ MEMORY WIDTHS ARE ALWAYS REPORTED AS 8 /!\ pub fn width(&self) -> u8 { match self { Operand::Nothing => { @@ -555,10 +559,12 @@ const REGISTER_CLASS_NAMES: &[&'static str] = &[ ]; 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::Q => 8, @@ -3185,15 +3191,22 @@ impl Instruction { self.opcode } + /// get the `Operand` at the provided index. + /// + /// panics if the index is `>= 4`. pub fn operand(&self, i: u8) -> Operand { assert!(i < 4); Operand::from_spec(self, self.operands[i as usize]) } + /// get the number of operands in this instruction. useful in iterating an instruction's + /// operands generically. pub fn operand_count(&self) -> u8 { self.operand_count } + /// check if operand `i` is an actual operand or not. will be `false` for `i >= + /// inst.operand_count()`. pub fn operand_present(&self, i: u8) -> bool { assert!(i < 4); if i >= self.operand_count { @@ -3207,6 +3220,8 @@ impl Instruction { } } + /// build a new instruction representing nothing in particular. this is primarily useful as a + /// default to pass to `decode_into`. pub fn invalid() -> Instruction { Instruction { prefixes: Prefixes::new(0), @@ -3657,7 +3672,7 @@ enum OperandCode { DX_AL = OperandCodeBuilder::new().special_case(47).bits(), MOVQ_f30f = OperandCodeBuilder::new().special_case(48).bits(), - Unsupported = OperandCodeBuilder::new().special_case(49).bits(), +// Unsupported = OperandCodeBuilder::new().special_case(49).bits(), ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(40).bits(), ModRM_0x0f01 = OperandCodeBuilder::new().read_modrm().special_case(41).bits(), @@ -6431,9 +6446,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[0] = OperandSpec::ImmU8; instruction.operand_count = 1; } + /* OperandCode::Unsupported => { return Err(DecodeError::IncompleteDecoder); } + */ OperandCode::Iw_Ib => { instruction.disp = read_num(&mut bytes_iter, 2)? as u64; instruction.imm = read_num(&mut bytes_iter, 1)? as u64; @@ -7446,7 +7463,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[1] = OperandSpec::Deref; instruction.operand_count = 2; } - // TODO: two memory operands! this is wrong!!! OperandCode::Yb_Xb => { instruction.operands[0] = OperandSpec::Deref_rdi; instruction.operands[1] = OperandSpec::Deref_rsi; @@ -8655,12 +8671,10 @@ fn imm_width_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> u if prefixes.rex().w() || !prefixes.operand_size() { 4 } else { 2 } }, SizeCode::vq => { - // TODO: this should be address_size - // but i'm not sure if that breaks other instructions rn if prefixes.operand_size() { 2 } else { - 8 // TODO: this 8 should be arch width. + 8 } }, SizeCode::vqp => { diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index cb19a15..315cb58 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -19,16 +19,6 @@ pub struct RegSpec { bank: RegisterBank } -impl RegSpec { - pub fn num(&self) -> u8 { - self.num - } - - pub fn class(&self) -> RegisterClass { - RegisterClass { kind: self.bank } - } -} - use core::hash::Hash; use core::hash::Hasher; impl Hash for RegSpec { @@ -70,6 +60,16 @@ pub enum ConditionCode { #[allow(non_snake_case)] impl RegSpec { + pub fn num(&self) -> u8 { + self.num + } + + pub fn class(&self) -> RegisterClass { + RegisterClass { kind: self.bank } + } + + /// return a human-friendly name for this register. the returned name is the same as would be + /// used to render this register in an instruction. pub fn name(&self) -> &'static str { display::regspec_label(self) } @@ -270,6 +270,7 @@ impl RegSpec { RegSpec { bank: RegisterBank::MM, num: 0 } } + /// return the size of this register, in bytes #[inline] pub fn width(&self) -> u8 { self.class().width() @@ -427,6 +428,10 @@ impl Operand { } } + /// return the width of this operand, in bytes. register widths are determined by the + /// register's class. + /// + /// TODO: /!\ MEMORY WIDTHS ARE ALWAYS REPORTED AS 8 /!\ pub fn width(&self) -> u8 { match self { Operand::Nothing => { @@ -3133,15 +3138,22 @@ impl Instruction { self.opcode } + /// get the `Operand` at the provided index. + /// + /// panics if the index is `>= 4`. pub fn operand(&self, i: u8) -> Operand { assert!(i < 4); Operand::from_spec(self, self.operands[i as usize]) } + /// get the number of operands in this instruction. useful in iterating an instruction's + /// operands generically. pub fn operand_count(&self) -> u8 { self.operand_count } + /// check if operand `i` is an actual operand or not. will be `false` for `i >= + /// inst.operand_count()`. pub fn operand_present(&self, i: u8) -> bool { assert!(i < 4); if i >= self.operand_count { @@ -3155,6 +3167,8 @@ impl Instruction { } } + /// build a new instruction representing nothing in particular. this is primarily useful as a + /// default to pass to `decode_into`. pub fn invalid() -> Instruction { Instruction { prefixes: Prefixes::new(0), @@ -3583,7 +3597,7 @@ enum OperandCode { DX_AL = OperandCodeBuilder::new().special_case(47).bits(), MOVQ_f30f = OperandCodeBuilder::new().special_case(48).bits(), - Unsupported = OperandCodeBuilder::new().special_case(49).bits(), +// Unsupported = OperandCodeBuilder::new().special_case(49).bits(), ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(40).bits(), ModRM_0x0f01 = OperandCodeBuilder::new().read_modrm().special_case(41).bits(), @@ -6390,9 +6404,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[0] = OperandSpec::ImmU8; instruction.operand_count = 1; } + /* OperandCode::Unsupported => { return Err(DecodeError::IncompleteDecoder); } + */ OperandCode::Iw_Ib => { instruction.disp = read_num(&mut bytes_iter, 2)?; instruction.imm = read_num(&mut bytes_iter, 1)?; @@ -7328,7 +7344,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[1] = OperandSpec::Deref; instruction.operand_count = 2; } - // TODO: two memory operands! this is wrong!!! OperandCode::Yb_Xb => { instruction.operands[0] = OperandSpec::Deref_edi; instruction.operands[1] = OperandSpec::Deref_esi; -- cgit v1.1