aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG8
-rw-r--r--Cargo.toml2
-rw-r--r--src/long_mode/mod.rs44
-rw-r--r--src/protected_mode/mod.rs39
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 <me@iximeow.net>" ]
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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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;