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