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