• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     Halted,
11     Break,
12     WatchWrite(u32),
13     WatchRead(u32),
14 }
15 
16 /// incredibly barebones armv4t-based emulator
17 pub struct Emu {
18     start_addr: u32,
19 
20     pub(crate) cpu: Cpu,
21     pub(crate) mem: ExampleMem,
22 
23     pub(crate) watchpoints: Vec<u32>,
24     pub(crate) breakpoints: Vec<u32>,
25 }
26 
27 impl Emu {
new(program_elf: &[u8]) -> DynResult<Emu>28     pub fn new(program_elf: &[u8]) -> DynResult<Emu> {
29         // set up emulated system
30         let mut cpu = Cpu::new();
31         let mut mem = ExampleMem::new();
32 
33         // load ELF
34         let elf_header = goblin::elf::Elf::parse(program_elf)?;
35 
36         // copy all in-memory sections from the ELF file into system RAM
37         let sections = elf_header
38             .section_headers
39             .iter()
40             .filter(|h| h.is_alloc() && h.sh_type != goblin::elf::section_header::SHT_NOBITS);
41 
42         for h in sections {
43             eprintln!(
44                 "loading section {:?} into memory from [{:#010x?}..{:#010x?}]",
45                 elf_header.shdr_strtab.get(h.sh_name).unwrap().unwrap(),
46                 h.sh_addr,
47                 h.sh_addr + h.sh_size,
48             );
49 
50             for (i, b) in program_elf[h.file_range()].iter().enumerate() {
51                 mem.w8(h.sh_addr as u32 + i as u32, *b);
52             }
53         }
54 
55         // setup execution state
56         eprintln!("Setting PC to {:#010x?}", elf_header.entry);
57         cpu.reg_set(Mode::User, reg::SP, 0x10000000);
58         cpu.reg_set(Mode::User, reg::LR, HLE_RETURN_ADDR);
59         cpu.reg_set(Mode::User, reg::PC, elf_header.entry as u32);
60         cpu.reg_set(Mode::User, reg::CPSR, 0x10); // user mode
61 
62         Ok(Emu {
63             start_addr: elf_header.entry as u32,
64             cpu,
65             mem,
66 
67             watchpoints: Vec::new(),
68             breakpoints: Vec::new(),
69         })
70     }
71 
reset(&mut self)72     pub(crate) fn reset(&mut self) {
73         self.cpu.reg_set(Mode::User, reg::SP, 0x10000000);
74         self.cpu.reg_set(Mode::User, reg::LR, HLE_RETURN_ADDR);
75         self.cpu.reg_set(Mode::User, reg::PC, self.start_addr);
76         self.cpu.reg_set(Mode::User, reg::CPSR, 0x10);
77     }
78 
step(&mut self) -> Option<Event>79     pub fn step(&mut self) -> Option<Event> {
80         let mut hit_watchpoint = None;
81 
82         let mut sniffer = MemSniffer::new(&mut self.mem, &self.watchpoints, |access| {
83             hit_watchpoint = Some(access)
84         });
85 
86         self.cpu.step(&mut sniffer);
87         let pc = self.cpu.reg_get(Mode::User, reg::PC);
88 
89         if let Some(access) = hit_watchpoint {
90             let fixup = if self.cpu.thumb_mode() { 2 } else { 4 };
91             self.cpu.reg_set(Mode::User, reg::PC, pc - fixup);
92 
93             return Some(match access.kind {
94                 AccessKind::Read => Event::WatchRead(access.addr),
95                 AccessKind::Write => Event::WatchWrite(access.addr),
96             });
97         }
98 
99         if self.breakpoints.contains(&pc) {
100             return Some(Event::Break);
101         }
102 
103         if pc == HLE_RETURN_ADDR {
104             return Some(Event::Halted);
105         }
106 
107         None
108     }
109 }
110