From 83b12fc09a69cc5324f6f002b8c52382d4b236d1 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 16 Dec 2023 15:54:13 -0800 Subject: fix incorrect register class names in long_mode also adjust changelog for a 1.2.1 version again, no new interfaces to go with these bugfixes. --- CHANGELOG | 5 +- .../does_not_decode_invalid_registers.rs | 270 +++++++++++++++++++++ src/long_mode/mod.rs | 8 +- 3 files changed, 278 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f471751..4653f57 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -## 1.3.0 +## 1.2.1 * fix incorrect register numbers used in `RegSpec::r12()` and `RegSpec::r13()` and smaller-size variants (thank you @tokatoka!) @@ -22,6 +22,9 @@ `vpmov*2m` with nonsense `k8..k15` selected. to real hardware, this bit sequence is an invalid instruction, and so it is now invalid to yaxpeax-x86 as well. +* fix incorrect `RegisterBank` names in `long_mode`. in a previous + reorganization register bank numbers were changed and the names were updated to + match for `protected_mode` and `real_mode`, but `long_mode` was overlooked. ## 1.2.0 * fix incorrect old yaxpeax-arch version selection for ffi crates diff --git a/fuzz/fuzz_targets/does_not_decode_invalid_registers.rs b/fuzz/fuzz_targets/does_not_decode_invalid_registers.rs index 0f32f73..31b1004 100644 --- a/fuzz/fuzz_targets/does_not_decode_invalid_registers.rs +++ b/fuzz/fuzz_targets/does_not_decode_invalid_registers.rs @@ -11,20 +11,290 @@ fuzz_target!(|data: &[u8]| { let x86_16_decoder = yaxpeax_x86::real_mode::InstDecoder::default(); if let Ok(inst) = x86_64_decoder.decode_slice(data) { + use yaxpeax_x86::long_mode::Operand; let mut res = String::new(); inst.write_to(&mut res).expect("format does not panic"); assert!(!res.contains("BUG")); + for i in 0..inst.operand_count() { + match inst.operand(i) { + Operand::Register(reg) => { + assert!(!reg.class().name().contains("BUG")); + } + Operand::RegisterMaskMerge(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegisterMaskMergeSae(r1, r2, _, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegisterMaskMergeSaeNoround(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDeref(r1) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegDisp(r1, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegScale(r1, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegIndexBase(r1, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseDisp(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegScaleDisp(r1, _, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegIndexBaseScale(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleDisp(r1, r2, _, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDerefMasked(r1, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDispMasked(r1, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegScaleMasked(r1, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseMasked(r1, r2, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegIndexBaseDispMasked(r1, r2, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegScaleDispMasked(r1, _, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleMasked(r1, r2, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleDispMasked(r1, r2, _, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::Nothing => { + panic!("`Nothing` should not be an operand listed in `inst.operand_count()`"); + } + _ => { + /* operands with no register - immediates or a non-rip-relative displacement */ + } + } + } }; if let Ok(inst) = x86_32_decoder.decode_slice(data) { + use yaxpeax_x86::protected_mode::Operand; let mut res = String::new(); inst.write_to(&mut res).expect("format does not panic"); assert!(!res.contains("BUG")); + for i in 0..inst.operand_count() { + match inst.operand(i) { + Operand::Register(reg) => { + assert!(!reg.class().name().contains("BUG")); + } + Operand::RegisterMaskMerge(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegisterMaskMergeSae(r1, r2, _, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegisterMaskMergeSaeNoround(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDeref(r1) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegDisp(r1, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegScale(r1, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegIndexBase(r1, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseDisp(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegScaleDisp(r1, _, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegIndexBaseScale(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleDisp(r1, r2, _, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDerefMasked(r1, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDispMasked(r1, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegScaleMasked(r1, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseMasked(r1, r2, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegIndexBaseDispMasked(r1, r2, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegScaleDispMasked(r1, _, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleMasked(r1, r2, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleDispMasked(r1, r2, _, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::Nothing => { + panic!("`Nothing` should not be an operand listed in `inst.operand_count()`"); + } + _ => { + /* operands with no register - immediates or a non-rip-relative displacement */ + } + } + } }; if let Ok(inst) = x86_16_decoder.decode_slice(data) { + use yaxpeax_x86::real_mode::Operand; let mut res = String::new(); inst.write_to(&mut res).expect("format does not panic"); assert!(!res.contains("BUG")); + for i in 0..inst.operand_count() { + match inst.operand(i) { + Operand::Register(reg) => { + assert!(!reg.class().name().contains("BUG")); + } + Operand::RegisterMaskMerge(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegisterMaskMergeSae(r1, r2, _, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegisterMaskMergeSaeNoround(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDeref(r1) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegDisp(r1, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegScale(r1, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegIndexBase(r1, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseDisp(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegScaleDisp(r1, _, _) => { + assert!(!r1.class().name().contains("BUG")); + } + Operand::RegIndexBaseScale(r1, r2, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleDisp(r1, r2, _, _) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDerefMasked(r1, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegDispMasked(r1, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegScaleMasked(r1, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseMasked(r1, r2, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegIndexBaseDispMasked(r1, r2, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegScaleDispMasked(r1, _, _, r2) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleMasked(r1, r2, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::RegIndexBaseScaleDispMasked(r1, r2, _, _, r3) => { + assert!(!r1.class().name().contains("BUG")); + assert!(!r2.class().name().contains("BUG")); + assert!(!r3.class().name().contains("BUG")); + } + Operand::Nothing => { + panic!("`Nothing` should not be an operand listed in `inst.operand_count()`"); + } + _ => { + /* operands with no register - immediates or a non-rip-relative displacement */ + } + } + } }; }); diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 4eb0a36..439417a 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -789,16 +789,16 @@ pub struct RegisterClass { } const REGISTER_CLASS_NAMES: &[&'static str] = &[ - "qword", - "BUG. PLEASE REPORT.", - "dword", "BUG. PLEASE REPORT.", + "byte", "word", "BUG. PLEASE REPORT.", - "byte", + "dword", "BUG. PLEASE REPORT.", "rex-byte", "BUG. PLEASE REPORT.", + "qword", + "BUG. PLEASE REPORT.", "cr", "BUG. PLEASE REPORT.", "dr", -- cgit v1.1