1 use armv4t_emu::{reg, Cpu, ExampleMem, Memory, Mode}; 2 3 use crate::mem_sniffer::{AccessKind, MemSniffer}; 4 use crate::DynResult; 5 6 const HLE_RETURN_ADDR: u32 = 0x12345678; 7 8 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 9 pub enum Event { 10 DoneStep, 11 Halted, 12 Break, 13 WatchWrite(u32), 14 WatchRead(u32), 15 } 16 17 pub enum ExecMode { 18 Step, 19 Continue, 20 RangeStep(u32, u32), 21 } 22 23 /// incredibly barebones armv4t-based emulator 24 pub struct Emu { 25 start_addr: u32, 26 27 // example custom register. only read/written to from the GDB client 28 pub(crate) custom_reg: u32, 29 30 pub(crate) exec_mode: ExecMode, 31 32 pub(crate) cpu: Cpu, 33 pub(crate) mem: ExampleMem, 34 35 pub(crate) watchpoints: Vec<u32>, 36 pub(crate) breakpoints: Vec<u32>, 37 pub(crate) files: Vec<Option<std::fs::File>>, 38 } 39 40 impl Emu { new(program_elf: &[u8]) -> DynResult<Emu>41 pub fn new(program_elf: &[u8]) -> DynResult<Emu> { 42 // set up emulated system 43 let mut cpu = Cpu::new(); 44 let mut mem = ExampleMem::new(); 45 46 // load ELF 47 let elf_header = goblin::elf::Elf::parse(program_elf)?; 48 49 // copy all in-memory sections from the ELF file into system RAM 50 let sections = elf_header 51 .section_headers 52 .iter() 53 .filter(|h| h.is_alloc() && h.sh_type != goblin::elf::section_header::SHT_NOBITS); 54 55 for h in sections { 56 eprintln!( 57 "loading section {:?} into memory from [{:#010x?}..{:#010x?}]", 58 elf_header.shdr_strtab.get_at(h.sh_name).unwrap(), 59 h.sh_addr, 60 h.sh_addr + h.sh_size, 61 ); 62 63 for (i, b) in program_elf[h.file_range().unwrap()].iter().enumerate() { 64 mem.w8(h.sh_addr as u32 + i as u32, *b); 65 } 66 } 67 68 // setup execution state 69 eprintln!("Setting PC to {:#010x?}", elf_header.entry); 70 cpu.reg_set(Mode::User, reg::SP, 0x10000000); 71 cpu.reg_set(Mode::User, reg::LR, HLE_RETURN_ADDR); 72 cpu.reg_set(Mode::User, reg::PC, elf_header.entry as u32); 73 cpu.reg_set(Mode::User, reg::CPSR, 0x10); // user mode 74 75 Ok(Emu { 76 start_addr: elf_header.entry as u32, 77 78 custom_reg: 0x12345678, 79 80 exec_mode: ExecMode::Continue, 81 82 cpu, 83 mem, 84 85 watchpoints: Vec::new(), 86 breakpoints: Vec::new(), 87 files: Vec::new(), 88 }) 89 } 90 reset(&mut self)91 pub(crate) fn reset(&mut self) { 92 self.cpu.reg_set(Mode::User, reg::SP, 0x10000000); 93 self.cpu.reg_set(Mode::User, reg::LR, HLE_RETURN_ADDR); 94 self.cpu.reg_set(Mode::User, reg::PC, self.start_addr); 95 self.cpu.reg_set(Mode::User, reg::CPSR, 0x10); 96 } 97 98 /// single-step the interpreter step(&mut self) -> Option<Event>99 pub fn step(&mut self) -> Option<Event> { 100 let mut hit_watchpoint = None; 101 102 let mut sniffer = MemSniffer::new(&mut self.mem, &self.watchpoints, |access| { 103 hit_watchpoint = Some(access) 104 }); 105 106 self.cpu.step(&mut sniffer); 107 let pc = self.cpu.reg_get(Mode::User, reg::PC); 108 109 if let Some(access) = hit_watchpoint { 110 let fixup = if self.cpu.thumb_mode() { 2 } else { 4 }; 111 self.cpu.reg_set(Mode::User, reg::PC, pc - fixup); 112 113 return Some(match access.kind { 114 AccessKind::Read => Event::WatchRead(access.addr), 115 AccessKind::Write => Event::WatchWrite(access.addr), 116 }); 117 } 118 119 if self.breakpoints.contains(&pc) { 120 return Some(Event::Break); 121 } 122 123 if pc == HLE_RETURN_ADDR { 124 return Some(Event::Halted); 125 } 126 127 None 128 } 129 130 /// run the emulator in accordance with the currently set `ExecutionMode`. 131 /// 132 /// since the emulator runs in the same thread as the GDB loop, the emulator 133 /// will use the provided callback to poll the connection for incoming data 134 /// every 1024 steps. run(&mut self, mut poll_incoming_data: impl FnMut() -> bool) -> RunEvent135 pub fn run(&mut self, mut poll_incoming_data: impl FnMut() -> bool) -> RunEvent { 136 match self.exec_mode { 137 ExecMode::Step => RunEvent::Event(self.step().unwrap_or(Event::DoneStep)), 138 ExecMode::Continue => { 139 let mut cycles = 0; 140 loop { 141 if cycles % 1024 == 0 { 142 // poll for incoming data 143 if poll_incoming_data() { 144 break RunEvent::IncomingData; 145 } 146 } 147 cycles += 1; 148 149 if let Some(event) = self.step() { 150 break RunEvent::Event(event); 151 }; 152 } 153 } 154 // just continue, but with an extra PC check 155 ExecMode::RangeStep(start, end) => { 156 let mut cycles = 0; 157 loop { 158 if cycles % 1024 == 0 { 159 // poll for incoming data 160 if poll_incoming_data() { 161 break RunEvent::IncomingData; 162 } 163 } 164 cycles += 1; 165 166 if let Some(event) = self.step() { 167 break RunEvent::Event(event); 168 }; 169 170 if !(start..end).contains(&self.cpu.reg_get(self.cpu.mode(), reg::PC)) { 171 break RunEvent::Event(Event::DoneStep); 172 } 173 } 174 } 175 } 176 } 177 } 178 179 pub enum RunEvent { 180 IncomingData, 181 Event(Event), 182 } 183