diff options
| -rw-r--r-- | src/lib.rs | 411 | 
1 files changed, 384 insertions, 27 deletions
| @@ -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<MSP430> for InstDecoder {      fn decode_into<T: Reader<<MSP430 as Arch>::Address, <MSP430 as Arch>::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), <MSP430 as Arch>::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<MSP430> for InstDecoder { +    type FieldDescription = MSP430FieldDescription; + +    fn decode_with_annotation< +        T: Reader<<MSP430 as Arch>::Address, <MSP430 as Arch>::Word>, +        S: DescriptionSink<Self::FieldDescription> +    >(&self, inst: &mut Instruction, words: &mut T, sink: &mut S) -> Result<(), <MSP430 as Arch>::DecodeError> {          let fullword = words.next()?.0; -        fn decode_operand<T: Reader<<MSP430 as Arch>::Address, <MSP430 as Arch>::Word>>(words: &mut T, reg: u8, mode: u8, oper: &mut Operand) -> Result<(), StandardDecodeError> { +        fn decode_operand< +            T: Reader<<MSP430 as Arch>::Address, <MSP430 as Arch>::Word>, +            S: DescriptionSink<MSP430FieldDescription> +        >(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<MSP430> 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<MSP430> 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<MSP430> 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<MSP430> 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<MSP430> 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(())              }          } | 
