From c903c7ece85d22f3ee310ebaaa73241402e0be70 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 12 Oct 2020 00:45:51 -0700 Subject: do not panic on invalid instructions --- Cargo.toml | 2 +- src/lib.rs | 46 +++++++++++++++++++++++++++++++++++----------- tests/test.rs | 9 +++++++++ 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8431e5d..e3f73d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yaxpeax-ia64" -version = "0.1.0" +version = "0.1.1" authors = ["iximeow "] edition = "2018" license = "0BSD" diff --git a/src/lib.rs b/src/lib.rs index c69083a..d0c7768 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1678,7 +1678,11 @@ impl Decoder for InstDecoder { let tag = word[37..41].load::(); let (opcode, operand_encoding) = get_l_opcode_and_encoding(tag, word); - let (dest_boundary, operands) = read_l_operands(operand_encoding, word, word2); + let (dest_boundary, operands) = if operand_encoding == OperandEncodingX::None { + (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) + } else { + read_l_operands(operand_encoding, word, word2) + }; Instruction { opcode, sf: None, @@ -1701,7 +1705,11 @@ impl Decoder for InstDecoder { match ty { InstructionType::I => { let (opcode, operand_encoding) = get_i_opcode_and_encoding(tag, word); - let (dest_boundary, operands) = read_i_operands(operand_encoding, word); + let (dest_boundary, operands) = if operand_encoding == OperandEncodingI::None { + (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) + } else { + read_i_operands(operand_encoding, word) + }; Instruction { opcode, sf: None, @@ -1753,7 +1761,11 @@ impl Decoder for InstDecoder { // storing an `sf` is fine } } - let (dest_boundary, mut operands) = read_f_operands(operand_encoding, word); + let (dest_boundary, mut operands) = if operand_encoding == OperandEncodingF::None { + (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) + } else { + read_f_operands(operand_encoding, word) + }; // quoth `fma - Floating-point Multiply Add`, fma.* with `f2` set to register // `f0` is actually `fmpy` // same `multiply-add` -> `multiply` applies for `xma` -> `xmpy` @@ -1812,7 +1824,11 @@ impl Decoder for InstDecoder { } else { word[0..6].load::() }; - let (dest_boundary, operands) = read_b_operands(operand_encoding, word); + let (dest_boundary, operands) = if operand_encoding == OperandEncodingB::None { + (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) + } else { + read_b_operands(operand_encoding, word) + }; Instruction { opcode, sf: None, @@ -1827,7 +1843,11 @@ impl Decoder for InstDecoder { }, InstructionType::A => { let (mut opcode, operand_encoding) = get_a_opcode_and_encoding(tag, word); - let (dest_boundary, mut operands) = read_a_operands(operand_encoding, word); + let (dest_boundary, mut operands) = if operand_encoding == OperandEncodingA::None { + (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) + } else { + read_a_operands(operand_encoding, word) + }; if opcode == Opcode::Addl { if operands[2] == Operand::GPRegister(GPRegister(0)) { opcode = Opcode::Mov; @@ -1851,7 +1871,11 @@ impl Decoder for InstDecoder { } InstructionType::M => { let (opcode, operand_encoding) = get_m_opcode_and_encoding(tag, word); - let (dest_boundary, operands) = read_m_operands(operand_encoding, word); + let (dest_boundary, operands) = if operand_encoding == OperandEncodingM::None { + (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) + } else { + read_m_operands(operand_encoding, word) + }; let mut hint = Some(word[28..30].load::()); // some `M` instructions don't actually have a hint, fix up after the fact. match (tag, word[30..36].load::()) { @@ -4492,7 +4516,7 @@ fn get_a_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, Ope } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingA { None, A1, @@ -4507,7 +4531,7 @@ enum OperandEncodingA { A10, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingI { None, I1, @@ -4542,7 +4566,7 @@ enum OperandEncodingI { I30, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingM { None, M1, @@ -4609,7 +4633,7 @@ enum OperandEncodingB { B9, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingF { None, F1, @@ -4631,7 +4655,7 @@ enum OperandEncodingF { } /// the manual is weird. encodings from `L`-unit instructions are named `X1`, `X2`, and so on. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingX { None, X1, diff --git a/tests/test.rs b/tests/test.rs index 729aed1..683818e 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -25,6 +25,15 @@ use yaxpeax_arch::Decoder; // 1000 2806 9811 5002 2000 4200 50a5 ff58 #[test] +fn test_invalid_instruction() { + let decoder = InstDecoder::default(); + + let expected = "[MII] (p07) mov r16=r0; (p09) mov r14=r0;; purple;;"; + let data = [0xe3, 0x80, 0x00, 0x00, 0x00, 0x61, 0xe2, 0x00, 0x00, 0x00, 0x42, 0xc0, 0xe1, 0x80, 0x30, 0x00]; + let inst = decoder.decode(data[..].iter().cloned()).unwrap(); + assert_eq!(format!("{}", inst), expected); +} +#[test] fn test_shr_shl_dep_ext() { // encoding of immediates for dep/ext and their pseudo-ops (shl/shr) is weird. // `pos` is recorded as `63 - the_actual_value`? `len` is encoded as the actual length minus -- cgit v1.1