From 34da4b9ceb5f6b2395dbf23ad6afdc5f473d29c2 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 3 Jan 2020 19:07:42 -0800 Subject: match changes in arch to have Resulty decode, instead of Option --- src/armv7.rs | 95 +++++++++++++++++++++++++++++++++++-------------------- src/armv8/a64.rs | 93 +++++++++++++++++++++++++++++++++-------------------- test/armv7.rs | 4 +-- test/armv8/a64.rs | 4 +-- 4 files changed, 123 insertions(+), 73 deletions(-) diff --git a/src/armv7.rs b/src/armv7.rs index 7d13c89..06f1287 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -1,7 +1,7 @@ //#[cfg(feature="use-serde")] //use serde::{Serialize, Deserialize}; -use std::fmt::{Display, Formatter}; +use std::fmt::{self, Display, Formatter}; use yaxpeax_arch::{Arch, Colorize, Colored, ColorSettings, Decoder, LengthedInstruction, ShowContextual, YaxColors}; @@ -437,6 +437,34 @@ pub struct Instruction { pub s: bool } +#[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 } +} + +impl yaxpeax_arch::Instruction for Instruction { + // TODO: this is wrong!! + fn well_defined(&self) -> bool { true } +} + #[allow(non_snake_case)] impl Instruction { pub fn blank() -> Instruction { @@ -673,29 +701,25 @@ pub struct InstDecoder {} #[allow(non_snake_case)] impl Decoder for InstDecoder { - fn decode>(&self, bytes: T) -> Option { + type Error = DecodeError; + + fn decode>(&self, bytes: T) -> Result { 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>(&self, inst: &mut Instruction, bytes: T) -> Option<()> { - fn read_word>(bytes: T) -> Option { + fn decode_into>(&self, inst: &mut Instruction, bytes: T) -> Result<(), Self::Error> { + fn read_word>(bytes: T) -> Result { let mut iter = bytes.into_iter(); let instr: u32 = - ((iter.next()? as u32) ) | - ((iter.next()? as u32) << 8 ) | - ((iter.next()? as u32) << 16) | - ((iter.next()? as u32) << 24); + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) ) | + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) << 8 ) | + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) << 16) | + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) << 24); - Some(instr) + Ok(instr) } - let word = match read_word(bytes) { - Some(word) => word, - None => { return None; } - }; + let word = read_word(bytes)?; let (cond, opc_upper) = { let top_byte = word >> 24; @@ -736,7 +760,7 @@ impl Decoder for InstDecoder { } else { inst.opcode = Opcode::Incomplete(word); } - return Some(()); + return Ok(()); } else { inst.condition = ConditionCode::build(cond); } @@ -784,7 +808,7 @@ impl Decoder for InstDecoder { 0b010 => { if s { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } inst.opcode = Opcode::UMAAL; inst.operands = Operands::MulFourRegs(R[2], R[3], R[0], R[1]); @@ -792,7 +816,7 @@ impl Decoder for InstDecoder { 0b011 => { if s { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } inst.opcode = Opcode::MLS; inst.operands = Operands::MulFourRegs(R[3], R[0], R[1], R[2]); @@ -846,7 +870,7 @@ impl Decoder for InstDecoder { }, 0b10001 | 0b10010 | 0b10011 => { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } 0b10100 => { inst.opcode = Opcode::SWPB; @@ -854,7 +878,7 @@ impl Decoder for InstDecoder { }, 0b10101 | 0b10110 | 0b10111 => { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } 0b11000 => { inst.opcode = Opcode::STREX; @@ -938,13 +962,13 @@ impl Decoder for InstDecoder { // |c o n d|0 0 0 x|x x x x x x x x x x x x x x x x|1 1 0 1|x x x x| // page A5-201 inst.opcode = Opcode::Incomplete(word); - return Some(()); + return Ok(()); } 0b11 => { // |c o n d|0 0 0 x|x x x x x x x x x x x x x x x x|1 1 1 1|x x x x| // page A5-201 inst.opcode = Opcode::Incomplete(word); - return Some(()); + return Ok(()); } _ => { unreachable!(); } } @@ -975,14 +999,14 @@ impl Decoder for InstDecoder { if opcode & 0b11 == 0b01 { inst.opcode = Opcode::BLX; inst.operands = Operands::OneOperand((word & 0x0f) as u8); - return Some(()); + return Ok(()); } else { - return None; + return Err(DecodeError::InvalidOpcode); } }, 0b100 => { inst.opcode = Opcode::Incomplete(word); - return Some(()); + return Ok(()); }, 0b101 => { @@ -1000,7 +1024,7 @@ impl Decoder for InstDecoder { // |c o n d|0 0 0|1 0 x x|0|x x x x|x x x x|x x x x|1|x x|x|x x x x| // multiply and multiply-accumulate inst.opcode = Opcode::Incomplete(word); - return Some(()); + return Ok(()); } } else { if opcode >= 16 { @@ -1057,7 +1081,7 @@ impl Decoder for InstDecoder { if (0b1101 & opcode) == 0b1101 { // these are all invalid inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } else { inst.operands = Operands::ThreeOperandWithShift(Rd, Rn, Rm, ShiftSpec::Register(shift_spec)); } @@ -1081,7 +1105,7 @@ impl Decoder for InstDecoder { // |c o n d|0 0 0|1 0 x x|0|x x x x|x x x x|x x x x x|x x|x|x x x x| // misc instructions (page A5-194) inst.opcode = Opcode::Incomplete(word); - return Some(()); + return Ok(()); } else { if opcode >= 16 { unreachable!(); @@ -1151,7 +1175,7 @@ impl Decoder for InstDecoder { if Rn == 0b1111 { inst.operands = Operands::RegImm(Rt, imm.into()); inst.opcode = Opcode::LDR(add, pre, wback); - return Some(()); + return Ok(()); } Opcode::LDR(add, pre, wback) }, @@ -1160,7 +1184,7 @@ impl Decoder for InstDecoder { if Rn == 0b1111 { inst.operands = Operands::RegImm(Rt, imm.into()); inst.opcode = Opcode::LDRB(add, pre, wback); - return Some(()); + return Ok(()); } Opcode::LDRB(add, pre, wback) }, @@ -1237,7 +1261,7 @@ impl Decoder for InstDecoder { }; inst.operands = Operands::ThreeOperandWithShift(Rn, Rt, Rm, ShiftSpec::Immediate(shift)); } - return Some(()); + return Ok(()); }, 0b100 | 0b101 => { // branch, branch with link, and block data transfer @@ -1273,11 +1297,11 @@ impl Decoder for InstDecoder { // coprocessor instructions and supervisor call // page A5-213 inst.opcode = Opcode::Incomplete(word); - return Some(()); + return Ok(()); }, _ => { unreachable!(); } } - Some(()) + Ok(()) } } @@ -1292,6 +1316,7 @@ pub struct ARMv7; impl Arch for ARMv7 { type Address = u32; type Instruction = Instruction; + type DecodeError = DecodeError; type Decoder = InstDecoder; type Operand = Operands; } diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 6dd9d68..0f2af3a 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -1,7 +1,7 @@ //#[cfg(feature="use-serde")] //use serde::{Serialize, Deserialize}; -use std::fmt::{Display, Formatter}; +use std::fmt::{self, Display, Formatter}; use yaxpeax_arch::{Arch, ColorSettings, Decoder, LengthedInstruction, ShowContextual}; @@ -126,6 +126,34 @@ mod docs { } } +#[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 } +} + +impl yaxpeax_arch::Instruction for Instruction { + // TODO: this is wrong!! + fn well_defined(&self) -> bool { true } +} + #[allow(non_snake_case)] impl ShowContextual], T> for Instruction { fn contextualize(&self, _colors: Option<&ColorSettings>, _address: u64, _context: Option<&[Option]>, out: &mut T) -> std::fmt::Result { @@ -144,6 +172,7 @@ pub struct ARMv8 { } impl Arch for ARMv8 { type Address = u64; type Instruction = Instruction; + type DecodeError = DecodeError; type Decoder = InstDecoder; type Operand = Operand; } @@ -981,29 +1010,25 @@ pub struct InstDecoder {} #[allow(non_snake_case)] impl Decoder for InstDecoder { - fn decode>(&self, bytes: T) -> Option { + type Error = DecodeError; + + fn decode>(&self, bytes: T) -> Result { 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>(&self, inst: &mut Instruction, bytes: T) -> Option<()> { - fn read_word>(bytes: T) -> Option { + fn decode_into>(&self, inst: &mut Instruction, bytes: T) -> Result<(), Self::Error> { + fn read_word>(bytes: T) -> Result { let mut iter = bytes.into_iter(); let instr: u32 = - ((iter.next()? as u32) ) | - ((iter.next()? as u32) << 8 ) | - ((iter.next()? as u32) << 16) | - ((iter.next()? as u32) << 24); + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) ) | + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) << 8 ) | + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) << 16) | + ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u32) << 24); - Some(instr) + Ok(instr) } - let word = match read_word(bytes) { - Some(word) => word, - None => { return None; } - }; + let word = read_word(bytes)?; #[derive(Copy, Clone, Debug)] enum Section { @@ -1079,7 +1104,7 @@ impl Decoder for InstDecoder { if opc2 == 0b000000 { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOperand); } let size_code = match word >> 29 { @@ -1138,7 +1163,7 @@ impl Decoder for InstDecoder { if word & 0x20000000 != 0 { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOperand); } let size = match sf_op | op2 { @@ -1183,7 +1208,7 @@ impl Decoder for InstDecoder { 0b1110 | 0b1111 => { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOpcode); }, _ => { unreachable!("sf, op, op2 are four bits total"); @@ -1238,7 +1263,7 @@ impl Decoder for InstDecoder { // technically this is undefined - do some // cores do something with this? inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOperand); } inst.opcode = Opcode::PACIZA; inst.operands = [ @@ -1321,7 +1346,7 @@ impl Decoder for InstDecoder { if (word >> 22) & 0x03 != 0 { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOperand); } let Rd = (word & 0x1f) as u16; @@ -1351,7 +1376,7 @@ impl Decoder for InstDecoder { let shift = (word >> 22) & 0x03; if shift == 0b11 { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOperand); } let Rd = (word & 0x1f) as u16; @@ -1361,7 +1386,7 @@ impl Decoder for InstDecoder { if size == SizeCode::W && imm6 >= 32 { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOperand); } inst.operands[0] = Operand::Register(size, Rd); @@ -1467,7 +1492,7 @@ impl Decoder for InstDecoder { 0b10 | 0b11 => { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOperand); } _ => { unreachable!("shift is two bits"); } }; @@ -1756,7 +1781,7 @@ impl Decoder for InstDecoder { (0b10, 0b1) => Opcode::LDAXRB, _ => { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } } } else if size == 0b01 { @@ -1767,7 +1792,7 @@ impl Decoder for InstDecoder { (0b10, 0b1) => Opcode::LDAXRH, _ => { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } } } else { @@ -1872,7 +1897,7 @@ impl Decoder for InstDecoder { (0b11, 0b10, 0b1) => Opcode::LDAR, // 64-bit _ => { inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } }; let size_code = if size == 0b11 { @@ -1939,7 +1964,7 @@ impl Decoder for InstDecoder { 0b11 => { // 11011100_XXXXXXXX_XXXXXXXX_XXXXXXXX inst.opcode = Opcode::Invalid; - return None; + return Err(DecodeError::InvalidOpcode); } _ => { unreachable!("opc is two bits"); @@ -2155,7 +2180,7 @@ impl Decoder for InstDecoder { if word & 0x200000 != 0 { if category != 0b10 { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOpcode); } else { // Load/store register (register offset) // C3.3.10 @@ -2236,7 +2261,7 @@ impl Decoder for InstDecoder { 0b00 | 0b01 => { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOpcode); }, 0b10 => { SizeCode::W } 0b11 => { SizeCode::X } @@ -2247,14 +2272,14 @@ impl Decoder for InstDecoder { 0b000 | 0b001 => { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOpcode); }, 0b010 => { ShiftStyle::UXTW }, 0b011 => { ShiftStyle::LSL }, 0b100 | 0b101 => { inst.opcode = Opcode::Invalid; - return Some(()); + return Err(DecodeError::InvalidOpcode); }, 0b110 => { ShiftStyle::SXTW }, 0b111 => { ShiftStyle::SXTX }, @@ -3013,6 +3038,6 @@ impl Decoder for InstDecoder { }, }; - Some(()) + Ok(()) } } diff --git a/test/armv7.rs b/test/armv7.rs index 7b0c2b6..fbd71ee 100644 --- a/test/armv7.rs +++ b/test/armv7.rs @@ -403,10 +403,10 @@ pub fn bench_60000_instrs(b: &mut Bencher) { let mut result = Instruction::blank(); loop { match decoder.decode_into(&mut result, &mut iter) { - Some(result) => { + Ok(result) => { test::black_box(&result); }, - None => { + Err(_) => { break; } } diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 4886fe1..406b867 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -2335,10 +2335,10 @@ pub fn bench_60000_instrs(b: &mut Bencher) { let mut result = Instruction::blank(); loop { match decoder.decode_into(&mut result, &mut iter) { - Some(result) => { + Ok(result) => { test::black_box(&result); }, - None => { + Err(_) => { break; } } -- cgit v1.1