1 use armv4t_emu::Memory; 2 3 #[derive(Debug)] 4 pub enum AccessKind { 5 Read, 6 Write, 7 } 8 9 #[derive(Debug)] 10 pub struct Access { 11 pub kind: AccessKind, 12 pub addr: u32, 13 // allow(dead_code) because the emulator is so simple that it doesn't matter 14 #[allow(dead_code)] 15 pub val: u32, 16 #[allow(dead_code)] 17 pub len: usize, 18 } 19 20 /// Wraps a `Memory` object, logging any accesses with the provided callback. 21 #[derive(Debug)] 22 pub struct MemSniffer<'a, M, F: FnMut(Access)> { 23 mem: &'a mut M, 24 addrs: &'a [u32], 25 on_access: F, 26 } 27 28 impl<'a, M: Memory, F: FnMut(Access)> MemSniffer<'a, M, F> { new(mem: &'a mut M, addrs: &'a [u32], on_access: F) -> MemSniffer<'a, M, F>29 pub fn new(mem: &'a mut M, addrs: &'a [u32], on_access: F) -> MemSniffer<'a, M, F> { 30 MemSniffer { 31 mem, 32 addrs, 33 on_access, 34 } 35 } 36 } 37 38 macro_rules! impl_memsniff_r { 39 ($fn:ident, $ret:ty) => { 40 fn $fn(&mut self, addr: u32) -> $ret { 41 let ret = self.mem.$fn(addr); 42 if self.addrs.contains(&addr) { 43 (self.on_access)(Access { 44 kind: AccessKind::Read, 45 addr, 46 val: ret as u32, 47 len: ret.to_le_bytes().len(), 48 }); 49 } 50 ret 51 } 52 }; 53 } 54 55 macro_rules! impl_memsniff_w { 56 ($fn:ident, $val:ty) => { 57 fn $fn(&mut self, addr: u32, val: $val) { 58 self.mem.$fn(addr, val); 59 if self.addrs.contains(&addr) { 60 (self.on_access)(Access { 61 kind: AccessKind::Write, 62 addr, 63 val: val as u32, 64 len: val.to_le_bytes().len(), 65 }); 66 } 67 } 68 }; 69 } 70 71 impl<'a, M: Memory, F: FnMut(Access)> Memory for MemSniffer<'a, M, F> { 72 impl_memsniff_r!(r8, u8); 73 impl_memsniff_r!(r16, u16); 74 impl_memsniff_r!(r32, u32); 75 impl_memsniff_w!(w8, u8); 76 impl_memsniff_w!(w16, u16); 77 impl_memsniff_w!(w32, u32); 78 } 79