From 35e325a7246d61d184b0336a89370d638bea0a81 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 6 Aug 2021 00:14:31 -0700 Subject: wip --- src/lib.rs | 411 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 384 insertions(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 71d9b4e..ea83289 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ extern crate serde; extern crate yaxpeax_arch; use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction, Reader, StandardDecodeError, U16le}; +use yaxpeax_arch::{AnnotatingDecoder, DescriptionSink, NullSink}; mod display; pub use display::NoContext; @@ -32,11 +33,24 @@ pub struct Instruction { pub operands: [Operand; 2] } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Width { W, B } +impl fmt::Display for Width { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Width::W => { + f.write_str("w") + } + Width::B => { + f.write_str("b") + } + } + } +} + impl Default for Instruction { fn default() -> Instruction { Instruction { @@ -72,7 +86,7 @@ impl LengthedInstruction for Instruction { } } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Opcode { Invalid(u16), RRC, @@ -104,7 +118,7 @@ pub enum Opcode { AND } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Operand { Register(u8), Indexed(u8, u16), @@ -171,51 +185,323 @@ impl Default for InstDecoder { impl Decoder for InstDecoder { fn decode_into::Address, ::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), ::DecodeError> { + self.decode_with_annotation(inst, words, &mut NullSink) + } +} + +#[derive(Clone, PartialEq, Eq)] +pub struct MSP430FieldDescription { + desc: Option<&'static str>, + value: MSP430Field, + // an opaque identifier to link different parts of FieldDescription at different offsets. + id: u32, +} + +#[derive(Clone, PartialEq, Eq)] +pub enum MSP430Field { + Opcode(Opcode), + Operand(Operand), + Width(Width), + None, +} + +use std::fmt; +impl fmt::Display for MSP430FieldDescription { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self.value { + MSP430Field::Opcode(opc) => { + write!(f, "opcode: {}", opc)?; + } + MSP430Field::Operand(operand) => { + write!(f, "operand: {}", operand)?; + } + MSP430Field::Width(width) => { + write!(f, "width: {}", width)?; + } + MSP430Field::None => { + } + } + + if let Some(desc) = self.desc { + if let MSP430Field::None = &self.value { + // no preceeding text, we can get right into the description + write!(f, "{}", desc)?; + } else { + // we printed something, add a separator for the description + write!(f, ", {}", desc)?; + } + } else { + // all done, no description to follow + } + + Ok(()) + } +} + +impl AnnotatingDecoder for InstDecoder { + type FieldDescription = MSP430FieldDescription; + + fn decode_with_annotation< + T: Reader<::Address, ::Word>, + S: DescriptionSink + >(&self, inst: &mut Instruction, words: &mut T, sink: &mut S) -> Result<(), ::DecodeError> { let fullword = words.next()?.0; - fn decode_operand::Address, ::Word>>(words: &mut T, reg: u8, mode: u8, oper: &mut Operand) -> Result<(), StandardDecodeError> { + fn decode_operand< + T: Reader<::Address, ::Word>, + S: DescriptionSink + >(words: &mut T, sink: &mut S, reg: u8, reg_addr: (u32, u32), mode: u8, mode_addr: (u32, u32), oper: &mut Operand) -> Result<(), StandardDecodeError> { + let id = reg_addr.0 + 256; *oper = match reg { 0 => { if mode == 0 { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("register number"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (register)"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); Operand::Register(reg) } else if mode == 1 { - Operand::Symbolic(words.next()?.0) + let disp_start = words.offset() as u32 * 16; + let disp = words.next()?.0; + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("operand mode (symbolic)"), + value: MSP430Field::Operand(Operand::Symbolic(disp)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (symbolic)"), + value: MSP430Field::Operand(Operand::Symbolic(disp)), + id + }); + sink.record(disp_start, disp_start + 15, MSP430FieldDescription { + desc: Some("pc-relative offst"), + value: MSP430Field::Operand(Operand::Symbolic(disp)), + id + }); + Operand::Symbolic(disp) } else if mode == 2 { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("register number"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (register)"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); Operand::RegisterIndirect(reg) } else if mode == 3 { - Operand::Immediate(words.next()?.0) + let imm_start = words.offset() as u32 * 16; + let imm = words.next()?.0; + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("operand mode (immediate)"), + value: MSP430Field::Operand(Operand::Immediate(imm)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (immediate)"), + value: MSP430Field::Operand(Operand::Immediate(imm)), + id + }); + sink.record(imm_start, imm_start + 15, MSP430FieldDescription { + desc: Some("immediate"), + value: MSP430Field::Operand(Operand::Immediate(imm)), + id + }); + Operand::Immediate(imm) } else { return Err(StandardDecodeError::InvalidOperand); } }, 2 => { match mode { - 0 => { Operand::Register(reg) }, + 0 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("register number"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (register)"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + Operand::Register(reg) + }, 1 => { - Operand::Absolute(words.next()?.0) + let abs_start = words.offset() as u32 * 16; + let abs = words.next()?.0; + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("operand mode (absolute)"), + value: MSP430Field::Operand(Operand::Absolute(abs)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (absolute)"), + value: MSP430Field::Operand(Operand::Absolute(abs)), + id + }); + sink.record(abs_start, abs_start + 15, MSP430FieldDescription { + desc: Some("absolute address"), + value: MSP430Field::Operand(Operand::Absolute(abs)), + id + }); + Operand::Absolute(abs) + }, + 2 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("constant (8)"), + value: MSP430Field::Operand(Operand::Const8), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("constant (8)"), + value: MSP430Field::Operand(Operand::Const8), + id + }); + Operand::Const8 + }, + 3 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("constant (4)"), + value: MSP430Field::Operand(Operand::Const4), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("constant (4)"), + value: MSP430Field::Operand(Operand::Const4), + id + }); + Operand::Const4 }, - 2 => { Operand::Const8 }, - 3 => { Operand::Const4 }, _ => { unreachable!() } } }, 3 => { match mode { - 0 => { Operand::Const0 }, - 1 => { Operand::Const1 }, - 2 => { Operand::Const2 }, - 3 => { Operand::ConstNeg1 }, + 0 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("constant (0)"), + value: MSP430Field::Operand(Operand::Const0), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("constant (0)"), + value: MSP430Field::Operand(Operand::Const0), + id + }); + Operand::Const0 + }, + 1 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("constant (1)"), + value: MSP430Field::Operand(Operand::Const1), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("constant (1)"), + value: MSP430Field::Operand(Operand::Const1), + id + }); + Operand::Const1 + }, + 2 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("constant (2)"), + value: MSP430Field::Operand(Operand::Const2), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("constant (2)"), + value: MSP430Field::Operand(Operand::Const2), + id + }); + Operand::Const2 + }, + 3 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("constant (-1)"), + value: MSP430Field::Operand(Operand::ConstNeg1), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("constant (-1)"), + value: MSP430Field::Operand(Operand::ConstNeg1), + id + }); + Operand::ConstNeg1 + }, _ => { unreachable!() } } }, _ => { match mode { - 0 => { Operand::Register(reg) }, + 0 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("register number"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (register)"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + Operand::Register(reg) + }, 1 => { - Operand::Indexed(reg, words.next()?.0) + let offset_start = words.offset() as u32 * 16; + let offset = words.next()?.0; + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("operand mode (indexed)"), + value: MSP430Field::Operand(Operand::Indexed(reg, offset)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (indexed)"), + value: MSP430Field::Operand(Operand::Indexed(reg, offset)), + id + }); + sink.record(offset_start, offset_start + 15, MSP430FieldDescription { + desc: Some("reg-relative offset"), + value: MSP430Field::Operand(Operand::Indexed(reg, offset)), + id + }); + Operand::Indexed(reg, offset) + }, + 2 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("register number"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (register indirect)"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + Operand::RegisterIndirect(reg) + }, + 3 => { + sink.record(reg_addr.0, reg_addr.1, MSP430FieldDescription { + desc: Some("register number"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + sink.record(mode_addr.0, mode_addr.1, MSP430FieldDescription { + desc: Some("operand mode (register indirect, autoinc)"), + value: MSP430Field::Operand(Operand::Register(reg)), + id + }); + Operand::IndirectAutoinc(reg) }, - 2 => { Operand::RegisterIndirect(reg) }, - 3 => { Operand::IndirectAutoinc(reg) }, _ => { unreachable!() } } } @@ -237,7 +523,18 @@ impl Decoder for InstDecoder { instrword if instrword < 0x2000 => { // microcorruption msp430 is non-standard and accepts invalid instructions.. if !self.microcorruption_quirks() { + sink.record(13, 15, MSP430FieldDescription { + desc: Some("unallocated opcode space (error)"), + value: MSP430Field::None, + id: 0, + }); return Err(StandardDecodeError::InvalidOpcode); + } else { + sink.record(13, 15, MSP430FieldDescription { + desc: Some("unallocated opcode space (microcorruption ignores)"), + value: MSP430Field::None, + id: 0, + }); } let (opcode_idx, operands) = ((instrword & 0x0380) >> 7, instrword & 0x7f); @@ -251,36 +548,67 @@ impl Decoder for InstDecoder { Opcode::PUSH, Opcode::CALL ][x as usize]; + sink.record(7, 9, MSP430FieldDescription { + desc: None, + value: MSP430Field::Opcode(inst.opcode), + id: 0, + }); inst.op_width = if operands & 0b01000000 == 0 { Width::W } else { - if x == 1 || x == 3 || x == 5 { - inst.opcode = Opcode::Invalid(instrword); - return Err(StandardDecodeError::InvalidOpcode); - } - Width:: B + Width::B }; + sink.record(6, 6, MSP430FieldDescription { + desc: None, + value: MSP430Field::Width(inst.op_width), + id: 1, + }); + if inst.op_width == Width::B && (x == 1 || x == 3 || x == 5) { + sink.record(6, 9, MSP430FieldDescription { + desc: Some("swpb, sxt, and call all require width=W (error)"), + value: MSP430Field::None, + id: 0, + }); + inst.opcode = Opcode::Invalid(instrword); + return Err(StandardDecodeError::InvalidOpcode); + } + #[allow(non_snake_case)] let (As, source) = ( ((instrword & 0x0030) >> 4) as u8, (instrword & 0x000f) as u8 ); - decode_operand(words, source, As, &mut inst.operands[0])?; + decode_operand(words, sink, source, (0, 3), As, (4, 5), &mut inst.operands[0])?; inst.operands[1] = Operand::Nothing; Ok(()) }, 6 => { + sink.record(7, 9, MSP430FieldDescription { + desc: None, + value: MSP430Field::Opcode(Opcode::RETI), + id: 0, + }); if operands == 0 { inst.opcode = Opcode::RETI; inst.operands[0] = Operand::Nothing; inst.operands[1] = Operand::Nothing; Ok(()) } else { + sink.record(0, 6, MSP430FieldDescription { + desc: Some("reti requires all-zero operands (error)"), + value: MSP430Field::None, + id: 0, + }); inst.opcode = Opcode::Invalid(instrword); return Err(StandardDecodeError::InvalidOperand); } } 7 => { + sink.record(7, 9, MSP430FieldDescription { + desc: Some("invalid opcode"), + value: MSP430Field::None, + id: 0, + }); inst.opcode = Opcode::Invalid(instrword); return Err(StandardDecodeError::InvalidOpcode); } @@ -301,7 +629,24 @@ impl Decoder for InstDecoder { Opcode::JL, Opcode::JMP ][opcode_idx as usize]; - inst.operands[0] = Operand::Offset(((offset as i16) << 6) >> 6); + sink.record(13, 15, MSP430FieldDescription { + desc: Some("Jcc or JMP"), + value: MSP430Field::Opcode(inst.opcode), + id: 0, + }); + sink.record(10, 12, MSP430FieldDescription { + desc: None, + value: MSP430Field::Opcode(inst.opcode), + id: 0, + }); + + let offset = ((offset as i16) << 6) >> 6; + sink.record(0, 9, MSP430FieldDescription { + desc: Some("relative offset (sign-extended to i16)"), + value: MSP430Field::Operand(Operand::Offset(offset)), + id: 2, + }); + inst.operands[0] = Operand::Offset(offset); inst.operands[1] = Operand::Nothing; Ok(()) }, @@ -321,7 +666,19 @@ impl Decoder for InstDecoder { Opcode::XOR, Opcode::AND ][(opcode_idx - 4) as usize]; + sink.record(12, 15, MSP430FieldDescription { + desc: None, + value: MSP430Field::Opcode(inst.opcode), + id: 0, + }); + inst.op_width = if operands & 0b01000000 == 0 { Width::W } else { Width:: B }; + sink.record(6, 6, MSP430FieldDescription { + desc: None, + value: MSP430Field::Width(inst.op_width), + id: 1, + }); + #[allow(non_snake_case)] let (source, Ad, As, dest) = ( ((instrword & 0x0f00) >> 8) as u8, @@ -329,8 +686,8 @@ impl Decoder for InstDecoder { ((instrword & 0x0030) >> 4) as u8, (instrword & 0x000f) as u8 ); - decode_operand(words, source, As, &mut inst.operands[0])?; - decode_operand(words, dest, Ad, &mut inst.operands[1])?; + decode_operand(words, sink, source, (8, 11), As, (4, 5), &mut inst.operands[0])?; + decode_operand(words, sink, dest, (0, 3), Ad, (7, 7), &mut inst.operands[1])?; Ok(()) } } -- cgit v1.1