diff options
| author | iximeow <me@iximeow.net> | 2021-07-06 16:42:24 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2021-07-06 16:43:02 -0700 | 
| commit | 61513023aff4d3312287bb0fb55ea931997dfddb (patch) | |
| tree | 51c07a11570d5012f68929e9c44a7fc2df97b15e | |
| parent | c75153a5efffcd2ac5f37864182e5108ea5f70ce (diff) | |
update yaxpeax_arch and bump version to 0.1.00.1.0
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | src/armv7.rs | 62 | ||||
| -rw-r--r-- | src/armv7/thumb.rs | 21 | ||||
| -rw-r--r-- | src/armv8/a64.rs | 43 | ||||
| -rw-r--r-- | test/armv7.rs | 23 | ||||
| -rw-r--r-- | test/armv7/thumb.rs | 29 | ||||
| -rw-r--r-- | test/armv8/a64.rs | 9 | 
7 files changed, 112 insertions, 79 deletions
| @@ -1,7 +1,7 @@  [package]  name = "yaxpeax-arm" -version = "0.0.7" +version = "0.1.0"  authors = [ "iximeow <me@iximeow.net>" ]  license = "0BSD"  repository = "http://git.iximeow.net/yaxpeax-arm/" @@ -9,7 +9,7 @@ description = "arm decoders for the yaxpeax project"  keywords = ["disassembler", "decoder", "armv7", "armv8"]  [dependencies] -yaxpeax-arch = { version = "0.0.5", default-features = false, features = [] } +yaxpeax-arch = { version = "0.2.2", default-features = false, features = [] }  bitvec = "0.19"  "serde" = { version = "1.0", optional = true }  "serde_derive" = { version = "1.0", optional = true } diff --git a/src/armv7.rs b/src/armv7.rs index b815218..82b7732 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -7,7 +7,7 @@  use std::fmt::{self, Display, Formatter}; -use yaxpeax_arch::{Arch, AddressDiff, Colorize, Decoder, LengthedInstruction, NoColors, ShowContextual, YaxColors}; +use yaxpeax_arch::{Arch, AddressDiff, Colorize, Decoder, LengthedInstruction, Reader, ReadError, NoColors, ShowContextual, YaxColors};  mod thumb; @@ -1565,7 +1565,7 @@ pub struct Instruction {      pub thumb: bool,  } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)]  pub enum DecodeError {      ExhaustedInput,      InvalidOpcode, @@ -1578,15 +1578,14 @@ pub enum DecodeError {  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"), -            DecodeError::Incomplete => write!(f, "incomplete decoder"), -            DecodeError::Nonconforming => write!(f, "invalid reserved bits"), -            DecodeError::Undefined => write!(f, "undefined encoding"), -            DecodeError::Unpredictable => write!(f, "unpredictable instruction"), -        } +        use yaxpeax_arch::DecodeError; +        f.write_str(self.description()) +    } +} + +impl From<ReadError> for DecodeError { +    fn from(_e: ReadError) -> DecodeError { +        DecodeError::ExhaustedInput      }  } @@ -1596,6 +1595,17 @@ impl yaxpeax_arch::DecodeError for DecodeError {      fn bad_operand(&self) -> bool {          self == &DecodeError::InvalidOperand || self == &DecodeError::Unpredictable      } +    fn description(&self) -> &'static str { +        match self { +            DecodeError::ExhaustedInput => "exhausted input", +            DecodeError::InvalidOpcode => "invalid opcode", +            DecodeError::InvalidOperand => "invalid operand", +            DecodeError::Incomplete => "incomplete decoder", +            DecodeError::Nonconforming => "invalid reserved bits", +            DecodeError::Undefined => "undefined encoding", +            DecodeError::Unpredictable => "unpredictable instruction", +        } +    }  }  impl yaxpeax_arch::Instruction for Instruction { @@ -2036,30 +2046,19 @@ impl InstDecoder {  }  #[allow(non_snake_case)] -impl Decoder<Instruction> for InstDecoder { -    type Error = DecodeError; - -    fn decode_into<T: IntoIterator<Item=u8>>(&self, inst: &mut Instruction, bytes: T) -> Result<(), Self::Error> { +impl Decoder<ARMv7> for InstDecoder { +    fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), <ARMv7 as Arch>::DecodeError> {          inst.set_w(false);          inst.set_wide(false);          if self.thumb { -            return thumb::decode_into(&self, inst, bytes); +            return thumb::decode_into(&self, inst, words);          } else {              inst.set_thumb(false);          } -        fn read_word<T: IntoIterator<Item=u8>>(bytes: T) -> Result<u32, DecodeError> { -            let mut iter = bytes.into_iter(); -            let instr: u32 = -                ((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); - -            Ok(instr) -        } - -        let word = read_word(bytes)?; +        let mut word_bytes = [0u8; 4]; +        words.next_n(&mut word_bytes)?; +        let word = u32::from_le_bytes(word_bytes);          let (cond, opc_upper) = {              let top_byte = word >> 24; @@ -3696,16 +3695,13 @@ impl Decoder<Instruction> for InstDecoder {      }  } -#[cfg(feature="use-serde")] -#[derive(Debug, Serialize, Deserialize)] -pub struct ARMv7; - -#[cfg(not(feature="use-serde"))] +#[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))]  #[derive(Debug)]  pub struct ARMv7;  impl Arch for ARMv7 {      type Address = u32; +    type Word = u8;      type Instruction = Instruction;      type DecodeError = DecodeError;      type Decoder = InstDecoder; diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs index 3c480af..8017f01 100644 --- a/src/armv7/thumb.rs +++ b/src/armv7/thumb.rs @@ -1,9 +1,12 @@  // use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction}; +use yaxpeax_arch::Arch; +use armv7::ARMv7;  use armv7::ConditionCode;  use armv7::DecodeError;  use armv7::CReg;  use armv7::Reg; +use armv7::Reader;  use armv7::RegShift;  use armv7::Operand;  use armv7::Opcode; @@ -97,20 +100,20 @@ fn DecodeImmShift(reg: u8, ty: u8, imm5: u8) -> RegShift {  }  #[allow(non_snake_case)] -pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut Instruction, bytes: T) -> Result<(), DecodeError> { +pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(decoder: &InstDecoder, inst: &mut Instruction, words: &mut T) -> Result<(), <ARMv7 as Arch>::DecodeError> {      // these are cleared in `armv7::InstDecoder::decode_into`.      // they must be reset when switching out of thumb decoding or decoding a new thumb instruction,      // which that `decode_into` is the entrypoint for in all cases.      // inst.set_w(false);      // inst.set_wide(false);      inst.set_thumb(true); -    let mut iter = bytes.into_iter(); -    let instr: u16 = -        ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16)      ) | -        ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16) << 8 ); +    let mut word_bytes = [0u8; 2]; +    words.next_n(&mut word_bytes)?; +    let word = u16::from_le_bytes(word_bytes); +    let instr = word;      let mut instr2 = bitarr![Lsb0, u16; 0u16; 16]; -    instr2[0..16].store(instr); +    instr2[0..16].store(word);      let opword = instr2[11..].load::<u16>(); @@ -122,9 +125,9 @@ pub fn decode_into<T: IntoIterator<Item=u8>>(decoder: &InstDecoder, inst: &mut I          // 32b instruction - `A6-228, 32-bit Thumb instruction encoding`          // opword low bits 01, 10, and 11 correspond to `op1` in table `A6-9` -        let lower: u16 = -            ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16)      ) | -            ((iter.next().ok_or(DecodeError::ExhaustedInput)? as u16) << 8 ); +        let mut word_bytes = [0u8; 2]; +        words.next_n(&mut word_bytes)?; +        let lower = u16::from_le_bytes(word_bytes);          let mut lower2 = bitarr![Lsb0, u16; 0u16; 16];          lower2[0..16].store(lower); diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 11b6499..2ef75d8 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -3,7 +3,7 @@  use std::fmt::{self, Display, Formatter}; -use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction, ShowContextual, YaxColors}; +use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction, Reader, ReadError, ShowContextual, YaxColors};  #[allow(non_snake_case)]  mod docs { @@ -135,11 +135,14 @@ pub enum DecodeError {  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"), -        } +        use yaxpeax_arch::DecodeError; +        f.write_str(self.description()) +    } +} + +impl From<ReadError> for DecodeError { +    fn from(_e: ReadError) -> DecodeError { +        DecodeError::ExhaustedInput      }  } @@ -147,6 +150,13 @@ 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 } +    fn description(&self) -> &'static str { +        match self { +            DecodeError::ExhaustedInput => "exhausted input", +            DecodeError::InvalidOpcode => "invalid opcode", +            DecodeError::InvalidOperand => "invalid operand", +        } +    }  }  impl yaxpeax_arch::Instruction for Instruction { @@ -171,6 +181,7 @@ pub struct ARMv8 { }  pub struct ARMv8 { }  impl Arch for ARMv8 { +    type Word = u8;      type Address = u64;      type Instruction = Instruction;      type DecodeError = DecodeError; @@ -1014,22 +1025,12 @@ impl Display for Operand {  pub struct InstDecoder {}  #[allow(non_snake_case)] -impl Decoder<Instruction> for InstDecoder { -    type Error = DecodeError; - -    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().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); - -            Ok(instr) -        } +impl Decoder<ARMv8> for InstDecoder { +    fn decode_into<T: Reader<<ARMv8 as Arch>::Address, <ARMv8 as Arch>::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), <ARMv8 as Arch>::DecodeError> { +        let mut word_bytes = [0u8; 4]; +        words.next_n(&mut word_bytes)?; +        let word = u32::from_le_bytes(word_bytes); -        let word = read_word(bytes)?;          #[derive(Copy, Clone, Debug)]          enum Section { diff --git a/test/armv7.rs b/test/armv7.rs index 6257f5b..7feb774 100644 --- a/test/armv7.rs +++ b/test/armv7.rs @@ -6,7 +6,8 @@ mod thumb;  type InstDecoder = <ARMv7 as Arch>::Decoder;  fn test_invalid_under(decoder: &InstDecoder, data: [u8; 4]) { -    match decoder.decode(data.to_vec()) { +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    match decoder.decode(&mut reader) {          Err(_) => { },          Ok(inst) => {              panic!( @@ -19,7 +20,13 @@ fn test_invalid_under(decoder: &InstDecoder, data: [u8; 4]) {  }  fn test_display_under(decoder: &InstDecoder, data: [u8; 4], expected: &'static str) { -    let instr = decoder.decode(data.to_vec()).unwrap_or_else(|_| panic!("failed to decode {:02x}{:02x}{:02x}{:02x}", data[0], data[1], data[2], data[3])); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let instr = match decoder.decode(&mut reader) { +        Err(e) => { +            panic!("failed to decode {:02x}{:02x}{:02x}{:02x}: {}", data[0], data[1], data[2], data[3], e) +        }, +        Ok(instr) => instr, +    };      let displayed = format!("{}", instr);      assert!(          displayed == expected, @@ -30,7 +37,8 @@ fn test_display_under(decoder: &InstDecoder, data: [u8; 4], expected: &'static s  }  fn test_decode(data: [u8; 4], expected: Instruction) { -    let instr = InstDecoder::default().decode(data.to_vec()).unwrap(); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let instr = InstDecoder::default().decode(&mut reader).unwrap();      assert!(          instr == expected,          "decode error for {:02x}{:02x}{:02x}{:02x}:\n  decoded: {:?}\n expected: {:?}\n", @@ -76,7 +84,8 @@ fn test_arm_security_extensions(data: [u8; 4], expected: &'static str) {  }  fn test_nonconformant(data: [u8; 4]) { -    let result = InstDecoder::default().decode(data.to_vec()); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let result = InstDecoder::default().decode(&mut reader);      assert!(          result == Err(DecodeError::Nonconforming),          "got bad result: {:?} from {:#x?}", result, data @@ -84,7 +93,8 @@ fn test_nonconformant(data: [u8; 4]) {  }  fn test_display(data: [u8; 4], expected: &'static str) { -    let instr = InstDecoder::default().decode(data.to_vec()).unwrap(); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let instr = InstDecoder::default().decode(&mut reader).unwrap();      let text = format!("{}", instr);      assert!(          text == expected, @@ -693,7 +703,8 @@ static INSTRUCTION_BYTES: [u8; 4 * 60] = [  fn test_decode_span() {      let mut i = 0u32;      while i < INSTRUCTION_BYTES.len() as u32 { -        let instr = InstDecoder::default().decode(INSTRUCTION_BYTES[(i as usize)..].iter().cloned()).unwrap(); +        let mut reader = yaxpeax_arch::U8Reader::new(&INSTRUCTION_BYTES[(i as usize)..]); +        let instr = InstDecoder::default().decode(&mut reader).unwrap();          println!(              "Decoded {:02x}{:02x}{:02x}{:02x}: {}", //{:?}\n  {}",              INSTRUCTION_BYTES[i as usize], diff --git a/test/armv7/thumb.rs b/test/armv7/thumb.rs index b603925..4c5c4a1 100644 --- a/test/armv7/thumb.rs +++ b/test/armv7/thumb.rs @@ -5,7 +5,8 @@ type InstDecoder = <ARMv7 as Arch>::Decoder;  #[allow(dead_code)]  fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) { -    match decoder.decode(data.to_vec()) { +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    match decoder.decode(&mut reader) {          Err(_) => { },          Ok(inst) => {              panic!( @@ -19,7 +20,13 @@ fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) {  #[allow(dead_code)]  fn test_display_under(decoder: &InstDecoder, data: [u8; 4], expected: &'static str) { -    let instr = decoder.decode(data.to_vec()).unwrap_or_else(|_| panic!("failed to decode {:#x?}", data)); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let instr = match decoder.decode(&mut reader) { +        Err(e) => { +            panic!("failed to decode {:#x?}: {}", data, e) +        } +        Ok(instr) => instr, +    };      let displayed = format!("{}", instr);      assert!(          displayed == expected, @@ -31,7 +38,13 @@ fn test_display_under(decoder: &InstDecoder, data: [u8; 4], expected: &'static s  #[allow(dead_code)]  fn test_decode(data: &[u8], expected: Instruction) { -    let instr = InstDecoder::default_thumb().decode(data.to_vec()).unwrap(); +    let mut reader = yaxpeax_arch::U8Reader::new(data); +    let instr = match InstDecoder::default_thumb().decode(&mut reader) { +        Err(e) => { +            panic!("failed to decode {:#x?}: {}", data, e) +        } +        Ok(instr) => instr, +    };      assert!(          instr == expected,          "decode error for {:#x?}:\n  decoded: {:?}\n expected: {:?}\n", @@ -42,11 +55,17 @@ fn test_decode(data: &[u8], expected: Instruction) {  #[allow(dead_code)]  fn test_invalid(data: &[u8]) { -   test_invalid_under(&InstDecoder::default(), data); +   test_invalid_under(&InstDecoder::default_thumb(), data);  }  fn test_display(data: &[u8], expected: &'static str) { -    let instr = InstDecoder::default_thumb().decode(data.to_vec()).unwrap(); +    let mut reader = yaxpeax_arch::U8Reader::new(data); +    let instr = match InstDecoder::default_thumb().decode(&mut reader) { +        Err(e) => { +            panic!("failed to decode {:#x?}: {}", data, e) +        } +        Ok(instr) => instr, +    };      let text = format!("{}", instr);      assert!(          text == expected, diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs index 90e6d6a..35a255d 100644 --- a/test/armv8/a64.rs +++ b/test/armv8/a64.rs @@ -2,7 +2,8 @@ use yaxpeax_arch::{Arch, Decoder, LengthedInstruction};  use yaxpeax_arm::armv8::a64::{ARMv8, Instruction, Operand, Opcode, SizeCode, ShiftStyle};  fn test_decode(data: [u8; 4], expected: Instruction) { -    let instr = <ARMv8 as Arch>::Decoder::default().decode(data.to_vec()).unwrap(); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let instr = <ARMv8 as Arch>::Decoder::default().decode(&mut reader).unwrap();      assert!(          instr == expected,          "decode error for {:02x}{:02x}{:02x}{:02x}:\n  decoded: {:?}\n expected: {:?}\n", @@ -12,7 +13,8 @@ fn test_decode(data: [u8; 4], expected: Instruction) {  }  fn test_display(data: [u8; 4], expected: &'static str) { -    let instr = <ARMv8 as Arch>::Decoder::default().decode(data.to_vec()).unwrap(); +    let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); +    let instr = <ARMv8 as Arch>::Decoder::default().decode(&mut reader).unwrap();      let text = format!("{}", instr);      assert!(          text == expected, @@ -2313,7 +2315,8 @@ static INSTRUCTION_BYTES: [u8; 4 * 61] = [  fn test_decode_span() {      let mut i = 0u64;      while i < INSTRUCTION_BYTES.len() as u64 { -        let instr = <ARMv8 as Arch>::Decoder::default().decode(INSTRUCTION_BYTES[(i as usize)..].iter().cloned()).unwrap(); +        let mut reader = yaxpeax_arch::U8Reader::new(&INSTRUCTION_BYTES[i as usize..]); +        let instr = <ARMv8 as Arch>::Decoder::default().decode(&mut reader).unwrap();          println!(              "Decoded {:02x}{:02x}{:02x}{:02x}: {}", //{:?}\n  {}",              INSTRUCTION_BYTES[i as usize], | 
