aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml4
-rw-r--r--src/armv7.rs62
-rw-r--r--src/armv7/thumb.rs21
-rw-r--r--src/armv8/a64.rs43
-rw-r--r--test/armv7.rs23
-rw-r--r--test/armv7/thumb.rs29
-rw-r--r--test/armv8/a64.rs9
7 files changed, 112 insertions, 79 deletions
diff --git a/Cargo.toml b/Cargo.toml
index f9b7284..54a13b1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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],