diff options
author | iximeow <me@iximeow.net> | 2020-10-12 00:45:51 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2020-10-12 00:45:51 -0700 |
commit | c903c7ece85d22f3ee310ebaaa73241402e0be70 (patch) | |
tree | 28232af2755765560bc23da2daccd2569c2a97ff | |
parent | 50fb66e30c6bd696461fe0855f5f4a1a48e83faa (diff) |
do not panic on invalid instructions
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/lib.rs | 46 | ||||
-rw-r--r-- | tests/test.rs | 9 |
3 files changed, 45 insertions, 12 deletions
@@ -1,6 +1,6 @@ [package] name = "yaxpeax-ia64" -version = "0.1.0" +version = "0.1.1" authors = ["iximeow <me@iximeow.net>"] edition = "2018" license = "0BSD" @@ -1678,7 +1678,11 @@ impl Decoder<InstructionBundle> for InstDecoder { let tag = word[37..41].load::<u8>(); 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<InstructionBundle> 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<InstructionBundle> 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<InstructionBundle> for InstDecoder { } else { word[0..6].load::<u8>() }; - 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<InstructionBundle> 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<InstructionBundle> 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::<u8>()); // some `M` instructions don't actually have a hint, fix up after the fact. match (tag, word[30..36].load::<u8>()) { @@ -4492,7 +4516,7 @@ fn get_a_opcode_and_encoding(tag: u8, word: &BitSlice<Lsb0, u8>) -> (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 |