1 use std::net::{TcpListener, TcpStream};
2
3 #[cfg(unix)]
4 use std::os::unix::net::{UnixListener, UnixStream};
5
6 use gdbstub::{Connection, DisconnectReason, GdbStub};
7
8 pub type DynResult<T> = Result<T, Box<dyn std::error::Error>>;
9
10 static TEST_PROGRAM_ELF: &[u8] = include_bytes!("test_bin/test.elf");
11
12 mod emu;
13 mod gdb;
14 mod mem_sniffer;
15
wait_for_tcp(port: u16) -> DynResult<TcpStream>16 fn wait_for_tcp(port: u16) -> DynResult<TcpStream> {
17 let sockaddr = format!("127.0.0.1:{}", port);
18 eprintln!("Waiting for a GDB connection on {:?}...", sockaddr);
19
20 let sock = TcpListener::bind(sockaddr)?;
21 let (stream, addr) = sock.accept()?;
22 eprintln!("Debugger connected from {}", addr);
23
24 Ok(stream)
25 }
26
27 #[cfg(unix)]
wait_for_uds(path: &str) -> DynResult<UnixStream>28 fn wait_for_uds(path: &str) -> DynResult<UnixStream> {
29 match std::fs::remove_file(path) {
30 Ok(_) => {}
31 Err(e) => match e.kind() {
32 std::io::ErrorKind::NotFound => {}
33 _ => return Err(e.into()),
34 },
35 }
36
37 eprintln!("Waiting for a GDB connection on {}...", path);
38
39 let sock = UnixListener::bind(path)?;
40 let (stream, addr) = sock.accept()?;
41 eprintln!("Debugger connected from {:?}", addr);
42
43 Ok(stream)
44 }
45
main() -> DynResult<()>46 fn main() -> DynResult<()> {
47 pretty_env_logger::init();
48
49 let mut emu = emu::Emu::new(TEST_PROGRAM_ELF)?;
50
51 let connection: Box<dyn Connection<Error = std::io::Error>> = {
52 if std::env::args().nth(1) == Some("--uds".to_string()) {
53 #[cfg(not(unix))]
54 {
55 return Err("Unix Domain Sockets can only be used on Unix".into());
56 }
57 #[cfg(unix)]
58 {
59 Box::new(wait_for_uds("/tmp/armv4t_gdb")?)
60 }
61 } else {
62 Box::new(wait_for_tcp(9001)?)
63 }
64 };
65
66 // hook-up debugger
67 let mut debugger = GdbStub::new(connection);
68
69 match debugger.run(&mut emu)? {
70 DisconnectReason::Disconnect => {
71 // run to completion
72 while emu.step() != Some(emu::Event::Halted) {}
73 }
74 DisconnectReason::TargetHalted => println!("Target halted!"),
75 DisconnectReason::Kill => {
76 println!("GDB sent a kill command!");
77 return Ok(());
78 }
79 }
80
81 let ret = emu.cpu.reg_get(armv4t_emu::Mode::User, 0);
82 println!("Program completed. Return value: {}", ret);
83
84 Ok(())
85 }
86