1use z3::{2 ast::{Array, BV},3 Context, Sort,4};56pub struct Memory<'ctx> {7 ctx: &'ctx Context,8 pub data: Array<'ctx>,9}1011impl<'ctx> Memory<'ctx> {12 pub fn new(ctx: &'ctx Context) -> Memory<'ctx> {13 let ary = Array::new_const(14 ctx,15 "memory",16 &Sort::bitvector(&ctx, 64), // index type17 &Sort::bitvector(&ctx, 8), // value type18 );1920 Memory {21 ctx: ctx,22 data: ary,23 }24 }2526 pub fn store_byte(&mut self, addr: BV<'ctx>, value: BV<'ctx>) {27 assert!(addr.get_size() == 64);28 assert!(value.get_size() == 8);29 self.data = self.data.store(&addr, &value);30 }3132 pub fn load_byte(&self, addr: BV<'ctx>) -> BV<'ctx> {33 assert!(addr.get_size() == 64);34 self.data.select(&addr).as_bv().unwrap()35 }3637 pub fn store_bitvector(&mut self, addr: BV<'ctx>, value: BV<'ctx>) {38 assert!(value.get_size() % 8 == 0);39 let amount = value.get_size() / 8;4041 // Extract nth bytes from the bitvector42 let bytes = (1..=amount)43 .into_iter()44 .rev()45 .map(|n| value.extract((n * 8) - 1, (n - 1) * 8));4647 // Store each byte in memory48 bytes.enumerate().for_each(|(n, b)| {49 assert!(b.get_size() == 8);50 self.store_byte(addr.bvadd(&BV::from_u64(self.ctx, n as u64, 64)), b)51 });52 }5354 pub fn load_bitvector(&self, addr: BV<'ctx>, amount: u64) -> BV<'ctx> {55 // Load amount bytes from memory56 let bytes = (0..amount)57 .into_iter()58 .map(|n| self.load_byte(addr.bvadd(&BV::from_u64(self.ctx, n, 64))));5960 // Concat the bytes into a single bitvector61 bytes.reduce(|acc, e| acc.concat(&e)).unwrap()62 }6364 pub fn store_string(&mut self, addr: BV<'ctx>, str: &str) -> BV<'ctx> {65 let mut cur_addr = addr;66 for c in str.chars() {67 let code: u8 = c.try_into().unwrap();68 self.store_byte(cur_addr.clone(), BV::from_u64(self.ctx, code.into(), 8));69 cur_addr = cur_addr.bvadd(&BV::from_u64(self.ctx, 1, 64));70 }7172 cur_addr73 }7475 pub fn store_word(&mut self, addr: BV<'ctx>, value: BV<'ctx>) {76 assert!(value.get_size() == 32);77 self.store_bitvector(addr, value)78 }7980 pub fn load_word(&self, addr: BV<'ctx>) -> BV<'ctx> {81 assert!(addr.get_size() == 64);82 self.load_bitvector(addr, 4)83 }84}8586#[cfg(test)]87mod tests {88 use super::*;89 use z3::ast::Ast;90 use z3::Config;91 use z3::SatResult;92 use z3::Solver;9394 #[test]95 fn test_byte() {96 let cfg = Config::new();97 let ctx = Context::new(&cfg);98 let mut mem = Memory::new(&ctx);99100 let addr = BV::from_u64(&ctx, 0x800000, 64);101 let value = BV::from_u64(&ctx, 0x23, 8);102103 mem.store_byte(addr.clone(), value.clone());104 let loaded = mem.load_byte(addr);105106 let solver = Solver::new(&ctx);107 solver.assert(&loaded._eq(&value));108 assert_eq!(SatResult::Sat, solver.check());109 }110111 #[test]112 fn test_string() {113 let cfg = Config::new();114 let ctx = Context::new(&cfg);115 let mut mem = Memory::new(&ctx);116117 let addr = BV::from_u64(&ctx, 0x0, 64);118 mem.store_string(addr, "hello");119 let loaded = mem.load_byte(BV::from_u64(&ctx, 0x0, 64));120121 let solver = Solver::new(&ctx);122 solver.assert(&loaded._eq(&BV::from_u64(&ctx, 0x68, 8)));123 assert_eq!(SatResult::Sat, solver.check());124 }125126 #[test]127 fn test_word() {128 let cfg = Config::new();129 let ctx = Context::new(&cfg);130 let mut mem = Memory::new(&ctx);131132 let addr = BV::from_u64(&ctx, 0x1000, 64);133 let word = BV::from_u64(&ctx, 0xdeadbeef, 32);134135 mem.store_word(addr.clone(), word.clone());136 let bytes = vec![137 mem.load_byte(BV::from_u64(&ctx, 0x1000, 64)),138 mem.load_byte(BV::from_u64(&ctx, 0x1001, 64)),139 mem.load_byte(BV::from_u64(&ctx, 0x1002, 64)),140 mem.load_byte(BV::from_u64(&ctx, 0x1003, 64)),141 ];142143 let solver = Solver::new(&ctx);144 solver.assert(&bytes[0]._eq(&BV::from_u64(&ctx, 0xde, 8)));145 solver.assert(&bytes[1]._eq(&BV::from_u64(&ctx, 0xad, 8)));146 solver.assert(&bytes[2]._eq(&BV::from_u64(&ctx, 0xbe, 8)));147 solver.assert(&bytes[3]._eq(&BV::from_u64(&ctx, 0xef, 8)));148 assert_eq!(SatResult::Sat, solver.check());149150 solver.reset();151152 let loaded_word = mem.load_word(addr);153 solver.assert(&loaded_word._eq(&word));154 assert_eq!(SatResult::Sat, solver.check());155 }156}