diff options
author | iximeow <me@iximeow.net> | 2020-01-10 02:29:27 -0800 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2020-01-12 17:00:47 -0800 |
commit | 1195e6fe7ec9db0aafdadaceac9290c80ba4eb50 (patch) | |
tree | 91524156f029729a59636ea341686275df8b0d1d | |
parent | e70be7245eac6acd6dde565c69b55bf8f55653e9 (diff) |
impl yaxpeax-arch instruction/decode interface
also fix panic on some immediate display in debug builds
-rw-r--r-- | src/display.rs | 6 | ||||
-rw-r--r-- | src/lib.rs | 55 |
2 files changed, 47 insertions, 14 deletions
diff --git a/src/display.rs b/src/display.rs index 036fb28..994880a 100644 --- a/src/display.rs +++ b/src/display.rs @@ -16,7 +16,7 @@ impl fmt::Display for Instruction { (Some(Operand::Reg(a)), Some(Operand::Reg(b)), Some(Operand::Imm(offs))) => { if a == b { if offs < 0 { - return write!(f, "b $-{:#x}", -offs); + return write!(f, "b $-{:#x}", offs.wrapping_neg()); } else { return write!(f, "b $+{:#x}", offs); } @@ -44,7 +44,7 @@ impl fmt::Display for Instruction { } } else if let Operand::Imm(imm) = op { if *imm < 0 { - return write!(f, "-{:#x}", -imm); + return write!(f, "-{:#x}", imm.wrapping_neg()); } else { return write!(f, "{:#x}", imm); } @@ -110,7 +110,7 @@ impl fmt::Display for Operand { write!(f, "({})", name) } else { if *offs < 0 { - write!(f, "-{:#x}({})", -offs, name) + write!(f, "-{:#x}({})", offs.wrapping_neg(), name) } else { write!(f, "{:#x}({})", offs, name) } @@ -2,6 +2,7 @@ extern crate num_enum; extern crate yaxpeax_arch; use std::convert::TryInto; +use std::fmt; use std::mem; use num_enum::IntoPrimitive; @@ -11,6 +12,30 @@ use yaxpeax_arch::{Arch, Decoder, LengthedInstruction}; mod display; #[derive(Debug, PartialEq)] +pub enum DecodeError { + ExhaustedInput, + InvalidOpcode, + InvalidOperand, +} + +impl fmt::Display for DecodeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DecodeError::ExhaustedInput => write!(f, "exhausted input"), + DecodeError::InvalidOpcode => write!(f, "invalid opcode"), + DecodeError::InvalidOperand => write!(f, "invalid operand"), + } + } +} + +impl yaxpeax_arch::DecodeError for DecodeError { + fn data_exhausted(&self) -> bool { self == &DecodeError::ExhaustedInput } + fn bad_opcode(&self) -> bool { self == &DecodeError::InvalidOpcode } + fn bad_operand(&self) -> bool { self == &DecodeError::InvalidOperand } +} + + +#[derive(Debug, PartialEq)] pub struct Instruction { word: u32, operands: [OperandSpec; 3], @@ -53,6 +78,13 @@ impl Instruction { } } +impl yaxpeax_arch::Instruction for Instruction { + fn well_defined(&self) -> bool { + // TODO: this is inaccurate + true + } +} + impl LengthedInstruction for Instruction { type Unit = u32; fn min_size() -> Self::Unit { @@ -231,6 +263,7 @@ pub struct MIPS; impl Arch for MIPS { type Address = u32; type Instruction = Instruction; + type DecodeError = DecodeError; type Decoder = MipsDecoder; type Operand = Operand; } @@ -239,18 +272,18 @@ impl Arch for MIPS { pub struct MipsDecoder {} impl Decoder<Instruction> for MipsDecoder { - fn decode<T: IntoIterator<Item=u8>>(&self, bytes: T) -> Option<Instruction> { + type Error = DecodeError; + + fn decode<T: IntoIterator<Item=u8>>(&self, bytes: T) -> Result<Instruction, Self::Error> { let mut blank = Instruction::blank(); - match self.decode_into(&mut blank, bytes) { - Some(_) => Some(blank), - None => None, - } + self.decode_into(&mut blank, bytes) + .map(|_: ()| blank) } - fn decode_into<T: IntoIterator<Item=u8>>(&self, instruction: &mut Instruction, bytes: T) -> Option<()> { + fn decode_into<T: IntoIterator<Item=u8>>(&self, instruction: &mut Instruction, bytes: T) -> Result<(), Self::Error> { let mut bytes_iter = bytes.into_iter(); let word: Vec<u8> = bytes_iter.by_ref().take(4).collect(); - let word = u32::from_le_bytes(word.as_slice().try_into().ok()?); + let word = u32::from_le_bytes(word.as_slice().try_into().map_err(|_| DecodeError::ExhaustedInput)?); instruction.word = word; @@ -263,7 +296,7 @@ impl Decoder<Instruction> for MipsDecoder { let opc = (word & 0b111111) as u8; if [0b000101, 0b001110, 0b010101, 0b101000, 0b101001, 0b110101, 0b110111, 0b111001, 0b111101].contains(&opc) { - return None; + return Err(DecodeError::InvalidOpcode); } // operands in the secondary map have kind of a mess of operands. except for 0b100000 @@ -325,7 +358,7 @@ impl Decoder<Instruction> for MipsDecoder { // reject all 0b11xxx patterns, and the right half of table A-40, section REGIMM, // except two outliers. if opc >= 0b10_011000 || (opc & 0b00_00100 > 0 && (opc != 0b10_001100 || opc != 0b10_001110)) { - return None; + return Err(DecodeError::InvalidOpcode); } instruction.opcode = unsafe { mem::transmute::<u8, Opcode>(opc) @@ -334,7 +367,7 @@ impl Decoder<Instruction> for MipsDecoder { } else { if opc & 0b111100 == 0b011100 || opc == 0b111011 { // reserved opcode - return None; + return Err(DecodeError::InvalidOpcode); } instruction.opcode = unsafe { mem::transmute::<u8, Opcode>(opc) @@ -372,7 +405,7 @@ impl Decoder<Instruction> for MipsDecoder { instruction.operands = [OperandSpec::Rt, OperandSpec::BaseOffset, OperandSpec::Nothing]; } } - return Some(()); + return Ok(()); } } |