mod computations;
mod equivalence;
use std::time::Duration;
use crate::arch::fake::{FakeArch, FakeReg, FakeState};
use crate::arch::x64::{GpReg, X64Arch, X64Reg};
use crate::encoding::bitpattern::Bit;
use crate::encoding::dataflows::{
AccessKind, AddressComputation, Dataflow, Dataflows, Dest, Inputs, MemoryAccess, MemoryAccesses, Size,
};
use crate::encoding::Encoding;
use crate::semantics::default::computation::{Arg, ArgEncoding, OutputEncoding, SynthesizedComputation};
use crate::semantics::default::ops::Op;
use crate::semantics::default::smtgen::{FilledLocation, Sizes, StorageLocations, Z3Model};
use crate::semantics::default::Expression;
use crate::semantics::IoType;
use crate::smt::z3::Z3Solver;
use crate::smt::{SatResult, SmtBV, SmtBVArray, SmtSolver};
use crate::state::{Addr, Location, MemoryState, Permissions, SystemState};
use crate::Instruction;
#[test]
pub fn array_store_select_equals() {
Z3Solver::with_thread_local(Duration::from_secs(900), |mut context| {
let arr = context.new_bv_array_const("mem", 64, 8);
let arr = arr.store(context.bv_from_u64(15, 64), context.bv_from_u64(42, 8));
let eq = !arr.select(context.bv_from_u64(15, 64))._eq(context.bv_from_u64(42, 8));
assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat));
});
}
#[test]
pub fn zero_register_is_zero() {
Z3Solver::with_thread_local(Duration::from_secs(900), |mut context| {
let mut s = StorageLocations::<X64Arch, _>::new(&mut context);
let key = FilledLocation::Concrete(Location::Reg(X64Reg::GpReg(GpReg::Riz)));
#[allow(deprecated)]
let riz = s.get(&mut context, key, &Sizes::default());
let eq = !riz._eq(context.bv_from_u64(0, 64));
assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat));
let riz = s.get_sized(&mut context, key, &Sizes::default(), Size::qword(), false);
let eq = !riz._eq(context.bv_from_u64(0, 64));
assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat));
let riz = s.get_raw(&mut context, key, &Sizes::default());
let eq = !riz._eq(context.bv_from_u64(0, 64));
assert!(matches!(context.check_assertions(&[eq]), SatResult::Unsat));
});
}
#[test]
pub fn identity_function_should_be_identical() {
use FakeReg::*;
let instr = Instruction::new(&[0x00]);
let encoding = Encoding {
bits: vec![Bit::Fixed(0); 8],
errors: vec![false; 8],
dataflows: Dataflows::<FakeArch, SynthesizedComputation> {
addresses: MemoryAccesses {
instr,
memory: vec![
MemoryAccess {
kind: AccessKind::Executable,
inputs: Inputs::sorted(vec![Dest::Reg(R0, Size::qword()).into()]),
size: 2..2,
calculation: AddressComputation::unscaled_sum(1),
alignment: 1,
},
MemoryAccess {
kind: AccessKind::InputOutput,
inputs: Inputs::sorted(vec![Dest::Reg(R1, Size::qword()).into()]),
size: 8..8,
calculation: AddressComputation::unscaled_sum(1),
alignment: 1,
},
MemoryAccess {
kind: AccessKind::InputOutput,
inputs: Inputs::sorted(vec![Dest::Reg(R2, Size::qword()).into()]),
size: 8..8,
calculation: AddressComputation::unscaled_sum(1),
alignment: 1,
},
],
use_trap_flag: false,
},
outputs: vec![Dataflow {
target: Dest::Mem(2, Size::new(0, 7)),
inputs: Inputs::sorted(vec![Dest::Mem(1, Size::new(0, 7)).into()]),
computation: Some(SynthesizedComputation::new(
Expression::new(vec![Op::Hole(0)]),
vec![Arg::Input {
index: 0,
num_bits: 64,
encoding: ArgEncoding::UnsignedLittleEndian,
}],
Vec::new(),
OutputEncoding::UnsignedLittleEndian,
IoType::Bytes {
num_bytes: 8,
},
)),
unobservable_external_inputs: false,
}],
found_dependent_bytes: false,
},
parts: Vec::new(),
write_ordering: Vec::new(),
};
let mut state = SystemState::new(
FakeState::default(),
MemoryState::new(
[
(Addr::new(0), Permissions::Execute, vec![0x00]),
(Addr::new(0), Permissions::ReadWrite, vec![1, 2, 3, 4, 5, 6, 7, 8]),
(Addr::new(0), Permissions::ReadWrite, vec![0; 8]),
]
.into_iter(),
),
);
encoding.dataflows.execute(&mut state);
assert_eq!(state.memory().get(2).2, vec![1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(state.memory().get(2).2, vec![1, 2, 3, 4, 5, 6, 7, 8]);
Z3Solver::with_thread_local(Duration::from_secs(900), |mut context| {
let mut storage = StorageLocations::<FakeArch, _>::new(&mut context);
let model = Z3Model::of(&encoding, &mut storage, &mut context);
let concrete = model.compute_concrete_outputs(&encoding, &mut storage, &mut context);
println!();
for item in model.constraints() {
println!("constraint: {item}");
}
assert_eq!(concrete.intermediate_values_needed(), &[] as &[usize]);
println!();
let output = concrete
.concrete_outputs()
.iter()
.find(|o| o.target() == Dest::Mem(2, Size::new(0, 7)))
.expect("should have Mem2 output");
let m2 = context.new_bv_const("m2_out", 64);
let m1 = context.new_bv_const("m1_in", 64);
let m1_val = storage
.get_sized(
&mut context,
FilledLocation::Concrete(Location::Memory(1)),
&Sizes::from_encoding(&encoding),
Size::new(0, 7),
true,
)
.extract(63, 0);
let assertions = [
m1.clone()._eq(m1_val.clone()),
m2.clone()._eq(output.smt().cloned().unwrap()),
!m1._eq(m2),
];
let result = context.check_assertions(&assertions);
match result {
SatResult::Unknown => unreachable!(),
SatResult::Sat(model) => panic!("found case where input m1 is not equal to output m2: {model:#?}"),
SatResult::Unsat => (),
}
});
}
#[test]
pub fn test_pdep() {
Z3Solver::with_thread_local(Duration::from_secs(900), |mut context| {
fn test<'ctx, S: SmtSolver<'ctx>>(context: &mut S, source: u64, mask: u64, expected: u64) {
let source_bv = context.new_bv_const("source", 64);
let mask_bv = context.new_bv_const("mask", 64);
let result_bv = context.new_bv_const("result", 64);
let result_val = context.deposit_bits::<64>(source_bv.clone(), mask_bv.clone());
let source_val = context.bv_from_u64(source, 64);
let mask_val = context.bv_from_u64(mask, 64);
let expected_val = context.bv_from_u64(expected, 64);
match context.check_assertions(&[
source_bv.clone()._eq(source_val),
mask_bv.clone()._eq(mask_val),
result_bv.clone()._eq(result_val),
!result_bv.clone()._eq(expected_val),
]) {
SatResult::Unknown => todo!(),
SatResult::Sat(model) => panic!("implementation incorrect: {model:?}, expected {expected:X?}"),
SatResult::Unsat => (),
}
}
test(&mut context, 0xffff_ffff_ffff_ffff, 0x123456789abcdef, 0x123456789abcdef);
test(
&mut context,
0xaaaa_aaaa_aaaa_aaaa,
0x0000_fffe_ffff_0078,
0x0000_5554_aaaa_0050,
);
});
}