aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-01-03 19:07:42 -0800
committeriximeow <me@iximeow.net>2020-01-12 17:29:01 -0800
commit34da4b9ceb5f6b2395dbf23ad6afdc5f473d29c2 (patch)
tree463cb5b8e6b0123200b90431c06d147ae70222fb
parent179d5d9cb7e94851ba69bf67f6d2dfbafa6aa6fe (diff)
match changes in arch to have Resulty decode, instead of Option
-rw-r--r--src/armv7.rs95
-rw-r--r--src/armv8/a64.rs93
-rw-r--r--test/armv7.rs4
-rw-r--r--test/armv8/a64.rs4
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<Instruction> for InstDecoder {
- 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, inst: &mut Instruction, bytes: T) -> Option<()> {
- fn read_word<T: IntoIterator<Item=u8>>(bytes: T) -> Option<u32> {
+ fn decode_into<T: IntoIterator<Item=u8>>(&self, inst: &mut Instruction, bytes: T) -> Result<(), Self::Error> {
+ fn read_word<T: IntoIterator<Item=u8>>(bytes: T) -> Result<u32, DecodeError> {
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<Instruction> for InstDecoder {
} else {
inst.opcode = Opcode::Incomplete(word);
}
- return Some(());
+ return Ok(());
} else {
inst.condition = ConditionCode::build(cond);
}
@@ -784,7 +808,7 @@ impl Decoder<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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 <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instruction {
fn contextualize(&self, _colors: Option<&ColorSettings>, _address: u64, _context: Option<&[Option<String>]>, 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<Instruction> for InstDecoder {
- 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, inst: &mut Instruction, bytes: T) -> Option<()> {
- fn read_word<T: IntoIterator<Item=u8>>(bytes: T) -> Option<u32> {
+ fn decode_into<T: IntoIterator<Item=u8>>(&self, inst: &mut Instruction, bytes: T) -> Result<(), Self::Error> {
+ fn read_word<T: IntoIterator<Item=u8>>(bytes: T) -> Result<u32, DecodeError> {
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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> for InstDecoder {
(0b10, 0b1) => Opcode::LDAXRH,
_ => {
inst.opcode = Opcode::Invalid;
- return None;
+ return Err(DecodeError::InvalidOpcode);
}
}
} else {
@@ -1872,7 +1897,7 @@ impl Decoder<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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<Instruction> 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;
}
}