#![no_std]
#[macro_use]
extern crate num_derive;
#[macro_use]
extern crate static_assertions;
#[cfg(feature = "std")]
extern crate std;
use core::convert::{TryFrom, TryInto};
use core::fmt;
use core::hash::{Hash, Hasher};
use num_traits::FromPrimitive;
use bad64_sys::*;
mod arrspec;
mod condition;
mod flageffect;
mod op;
mod operand;
mod reg;
mod shift;
mod sysreg;
pub use arrspec::ArrSpec;
pub use condition::Condition;
pub use flageffect::FlagEffect;
pub use op::Op;
pub use operand::{Imm, Operand};
pub use reg::Reg;
pub use shift::Shift;
pub use sysreg::SysReg;
#[derive(Clone)]
pub struct Instruction {
address: u64,
opcode: u32,
op: Op,
num_operands: usize,
operands: [Operand; MAX_OPERANDS as usize],
flags_set: Option<FlagEffect>,
}
impl PartialEq for Instruction {
fn eq(&self, other: &Self) -> bool {
self.address() == other.address()
&& self.op() == other.op()
&& self.opcode() == other.opcode()
&& self.num_operands == other.num_operands
&& self.flags_set == other.flags_set
&& self
.operands()
.iter()
.zip(other.operands().iter())
.all(|(a, b)| a == b)
}
}
impl Eq for Instruction {}
impl Hash for Instruction {
fn hash<H: Hasher>(&self, state: &mut H) {
self.address.hash(state);
self.opcode.hash(state);
self.op.hash(state);
self.num_operands.hash(state);
self.flags_set.hash(state);
for o in self.operands() {
o.hash(state);
}
}
}
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.op())?;
let mut ops = self.operands().iter();
if let Some(op) = ops.next() {
write!(f, " {}", op)?;
for op in ops {
write!(f, ", {}", op)?;
}
}
Ok(())
}
}
impl fmt::Debug for Instruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Instruction")
.field("address", &self.address)
.field("opcode", &self.opcode)
.field("op", &self.op)
.field("num_operands", &self.num_operands)
.field("operands", &self.operands())
.field("flags_set", &self.flags_set)
.finish()
}
}
impl Instruction {
pub fn address(&self) -> u64 {
self.address
}
pub fn opcode(&self) -> u32 {
self.opcode
}
pub fn op(&self) -> Op {
self.op
}
pub fn operands(&self) -> &[Operand] {
&self.operands[..self.num_operands]
}
pub fn flags_set(&self) -> Option<FlagEffect> {
self.flags_set
}
}
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
#[repr(i32)]
pub enum DecodeError {
Reserved(u64),
Unmatched(u64),
Unallocated(u64),
Undefined(u64),
EndOfInstruction(u64),
Lost(u64),
Unreachable(u64),
Short(u64),
ErrorOperands(u64),
}
impl DecodeError {
fn new(code: i32, address: u64) -> Self {
match code {
DECODE_STATUS_RESERVED => Self::Reserved(address),
DECODE_STATUS_UNMATCHED => Self::Unmatched(address),
DECODE_STATUS_UNALLOCATED => Self::Unallocated(address),
DECODE_STATUS_UNDEFINED => Self::Undefined(address),
DECODE_STATUS_END_OF_INSTRUCTION => Self::EndOfInstruction(address),
DECODE_STATUS_LOST => Self::Lost(address),
DECODE_STATUS_UNREACHABLE => Self::Unreachable(address),
DECODE_STATUS_ERROR_OPERANDS => Self::ErrorOperands(address),
_ => panic!("unknown decode error code"),
}
}
pub fn address(&self) -> u64 {
match self {
Self::Reserved(a) => *a,
Self::Unmatched(a) => *a,
Self::Unallocated(a) => *a,
Self::Undefined(a) => *a,
Self::EndOfInstruction(a) => *a,
Self::Lost(a) => *a,
Self::Unreachable(a) => *a,
Self::Short(a) => *a,
Self::ErrorOperands(a) => *a,
}
}
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DecodeError::Reserved(x) => write!(f, "Reserved: {:#x}", x),
DecodeError::Unmatched(x) => write!(f, "Unmatched: {:#x}", x),
DecodeError::Unallocated(x) => write!(f, "Unallocated: {:#x}", x),
DecodeError::Undefined(x) => write!(f, "Undefined: {:#x}", x),
DecodeError::EndOfInstruction(x) => write!(f, "EndOfInstruction: {:#x}", x),
DecodeError::Lost(x) => write!(f, "Lost: {:#x}", x),
DecodeError::Unreachable(x) => write!(f, "Unreachable: {:#x}", x),
DecodeError::Short(x) => write!(f, "Short: {:#x}", x),
DecodeError::ErrorOperands(x) => write!(f, "ErrorOperands: {:#x}", x),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}
pub fn decode(ins: u32, address: u64) -> Result<Instruction, DecodeError> {
let (r, decoded) = unsafe {
let mut decoded: bad64_sys::Instruction = core::mem::zeroed();
let r = aarch64_decompose(ins, &mut decoded, address);
(r, decoded)
};
match r {
0 => {
assert_ne!(decoded.operation, Operation_ARM64_ERROR);
let op = Op::from_u32(decoded.operation as u32).unwrap();
let mut operands: [Operand; MAX_OPERANDS as usize] =
[Operand::Label(Imm::Unsigned(0)); MAX_OPERANDS as usize];
let mut num_operands = 0;
for (n, operand) in decoded.operands.iter().enumerate() {
match Operand::try_from(operand) {
Ok(o) => {
operands[n] = o;
num_operands += 1;
}
Err(_) => break,
}
}
let flags_set = FlagEffect::try_from(&decoded).ok();
Ok(Instruction {
address,
opcode: decoded.insword,
op,
num_operands,
operands,
flags_set,
})
}
_ => Err(DecodeError::new(r, address)),
}
}
pub fn disasm(
code: &[u8],
address: u64,
) -> impl Iterator<Item = Result<Instruction, DecodeError>> + '_ {
(address..)
.step_by(4)
.zip(code.chunks(4))
.map(|(addr, bytes)| match bytes.try_into() {
Ok(v) => {
let vv = u32::from_le_bytes(v);
decode(vv, addr)
}
Err(_) => Err(DecodeError::Short(addr)),
})
}