pub mod decode;
mod mutate;
#[derive(Clone, Copy, Default, PartialOrd, PartialEq)]
pub struct Insn(pub(crate) u32);
impl Insn {
pub fn bx_lr() -> Self {
Self(0xe12fff1e)
}
pub fn pop(r: &[crate::armv4t::isa::decode::Register]) -> Self {
use crate::armv4t::isa::decode::Register;
let mut i = 0xe8bd0000u32;
for reg in [
Register::R0,
Register::R1,
Register::R2,
Register::R3,
Register::R4,
Register::R5,
Register::R6,
Register::R7,
Register::R8,
Register::R9,
Register::R10,
Register::R11,
Register::R12,
Register::Lr,
Register::Sp,
Register::Pc,
]
.iter()
.enumerate()
{
if r.contains(reg.1) {
i |= 1 << (reg.0 as u32);
}
}
Self(i)
}
pub fn push(r: &[crate::armv4t::isa::decode::Register]) -> Self {
use crate::armv4t::isa::decode::Register;
let mut i = 0xe92d0000u32;
for reg in [
Register::R0,
Register::R1,
Register::R2,
Register::R3,
Register::R4,
Register::R5,
Register::R6,
Register::R7,
Register::R8,
Register::R9,
Register::R10,
Register::R11,
Register::R12,
Register::Lr,
Register::Sp,
Register::Pc,
]
.iter()
.enumerate()
{
if r.contains(reg.1) {
i |= 1 << (reg.0 as u32);
}
}
Self(i)
}
pub fn fixup(&mut self) -> bool {
true
}
pub fn increment(&mut self) -> crate::IterationResult {
if self.0 > 0xfffffffe {
Err(crate::StepError::End)
} else {
self.0 += 1;
Ok(())
}
}
fn make_return(&mut self) -> crate::IterationResult {
use std::cmp::Ordering;
match self.0.cmp(&Self::bx_lr().0) {
Ordering::Less => {
*self = Self::bx_lr();
Ok(())
}
Ordering::Greater => Err(crate::StepError::End),
Ordering::Equal => unreachable!(),
}
}
}
impl crate::Step for Insn {
fn first() -> Self {
Insn(0)
}
fn next(&mut self) -> crate::IterationResult {
self.increment()
}
}
impl crate::subroutine::ShouldReturn for Insn {
fn should_return(&self, offset: usize) -> Result<(), crate::StaticAnalysis<Self>> {
if *self == Self::bx_lr() {
return Ok(());
}
Err(crate::StaticAnalysis::<Self> {
advance: Self::make_return,
offset,
reason: "ShouldReturn",
})
}
}
impl crate::Encode<u8> for Insn {
fn encode(&self) -> Vec<u8> {
self.0.to_le_bytes().to_vec()
}
}
impl crate::Encode<u32> for Insn {
fn encode(&self) -> Vec<u32> {
vec![self.0]
}
}
impl crate::Disassemble for Insn {
fn dasm(&self) {
println!("\t{:?}", self);
}
}
impl crate::Branch for Insn {}
#[cfg(test)]
mod test {
fn emulator_knows_it(i9n: super::Insn) -> bool {
use crate::Encode;
use armv4t_emu::{reg, Cpu, ExampleMem, Mode};
let mut mem = ExampleMem::new_with_data(&i9n.encode());
let mut cpu = Cpu::new();
cpu.reg_set(Mode::User, reg::PC, 0x00);
cpu.reg_set(Mode::User, reg::CPSR, 0x10);
cpu.step(&mut mem)
}
#[test]
fn bx_lr() {
assert_eq!("bx lr", &format!("{}", super::Insn::bx_lr()));
}
#[test]
fn should_return() {
use crate::subroutine::ShouldReturn;
use crate::Step;
let mut i = super::Insn::first();
let sa = i.should_return(0).err().unwrap();
(sa.advance)(&mut i).unwrap();
assert_eq!(i, super::Insn::bx_lr());
assert!(i.should_return(0).is_ok());
i.next().unwrap();
let sa = i.should_return(0).err().unwrap();
assert!((sa.advance)(&mut i).is_err());
}
#[test]
#[ignore]
fn all_instructions() {
use crate::Step;
let mut i = super::Insn(0xff7affff);
while i.next().is_ok() {
assert_eq!(format!("{:?}", i).len(), 95, "{:?}", i);
assert!(!format!("{:?}", i).contains("illegal"), "{:?}", i);
if !emulator_knows_it(i) {
let beginning = i;
let mut end = i;
while !emulator_knows_it(i) {
end = i;
println!("the emulator can't run {:?}", i);
i.next().unwrap();
}
println!("the range is {:?}..{:?} inclusive", beginning.0, end.0);
panic!("found a range of instructions visited by the .increment method that the emulator doesn't know");
}
}
}
}