Stub out reading registers and memory
This commit is contained in:
		
							parent
							
								
									9519897711
								
							
						
					
					
						commit
						d016538408
					
				| 
						 | 
					@ -397,6 +397,15 @@ dependencies = [
 | 
				
			||||||
 "syn",
 | 
					 "syn",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "atoi"
 | 
				
			||||||
 | 
					version = "2.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "atomic-waker"
 | 
					name = "atomic-waker"
 | 
				
			||||||
version = "1.1.2"
 | 
					version = "1.1.2"
 | 
				
			||||||
| 
						 | 
					@ -1742,6 +1751,7 @@ name = "lemur"
 | 
				
			||||||
version = "0.2.5"
 | 
					version = "0.2.5"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "anyhow",
 | 
					 "anyhow",
 | 
				
			||||||
 | 
					 "atoi",
 | 
				
			||||||
 "bitflags 2.6.0",
 | 
					 "bitflags 2.6.0",
 | 
				
			||||||
 "bytemuck",
 | 
					 "bytemuck",
 | 
				
			||||||
 "cc",
 | 
					 "cc",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
anyhow = "1"
 | 
					anyhow = "1"
 | 
				
			||||||
 | 
					atoi = "2"
 | 
				
			||||||
bitflags = { version = "2", features = ["serde"] }
 | 
					bitflags = { version = "2", features = ["serde"] }
 | 
				
			||||||
bytemuck = { version = "1", features = ["derive"] }
 | 
					bytemuck = { version = "1", features = ["derive"] }
 | 
				
			||||||
clap = { version = "4", features = ["derive"] }
 | 
					clap = { version = "4", features = ["derive"] }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,6 +212,33 @@ impl GdbConnection {
 | 
				
			||||||
            } else if req.match_str("c") || req.match_str("vCont;c:") {
 | 
					            } else if req.match_str("c") || req.match_str("vCont;c:") {
 | 
				
			||||||
                self.client.send_command(EmulatorCommand::Resume);
 | 
					                self.client.send_command(EmulatorCommand::Resume);
 | 
				
			||||||
                // Don't send a response until we hit a breakpoint or get interrupted
 | 
					                // Don't send a response until we hit a breakpoint or get interrupted
 | 
				
			||||||
 | 
					            } else if req.match_str("p") {
 | 
				
			||||||
 | 
					                let Some(register) = req.match_hex::<u32>() else {
 | 
				
			||||||
 | 
					                    let res = self.response();
 | 
				
			||||||
 | 
					                    self.send(res).await?;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let res = self.response().write_hex(register);
 | 
				
			||||||
 | 
					                self.send(res).await?;
 | 
				
			||||||
 | 
					            } else if req.match_str("m") {
 | 
				
			||||||
 | 
					                let mut read_params = || {
 | 
				
			||||||
 | 
					                    let start = req.match_hex::<u32>()?;
 | 
				
			||||||
 | 
					                    if !req.match_str(",") {
 | 
				
			||||||
 | 
					                        return None;
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let size = req.match_hex::<u32>()?;
 | 
				
			||||||
 | 
					                    Some((start, size))
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let Some((start, size)) = read_params() else {
 | 
				
			||||||
 | 
					                    let res = self.response();
 | 
				
			||||||
 | 
					                    self.send(res).await?;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let mut res = self.response();
 | 
				
			||||||
 | 
					                for i in 0..size {
 | 
				
			||||||
 | 
					                    res = res.write_hex((start + i) as u8);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                self.send(res).await?;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // unrecognized command
 | 
					                // unrecognized command
 | 
				
			||||||
                let res = self.response();
 | 
					                let res = self.response();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
use anyhow::{bail, Result};
 | 
					use anyhow::{bail, Result};
 | 
				
			||||||
 | 
					use atoi::FromRadix16;
 | 
				
			||||||
use tokio::io::{AsyncRead, AsyncReadExt as _};
 | 
					use tokio::io::{AsyncRead, AsyncReadExt as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 | 
					#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 | 
				
			||||||
| 
						 | 
					@ -6,11 +7,32 @@ pub enum RequestKind {
 | 
				
			||||||
    Signal,
 | 
					    Signal,
 | 
				
			||||||
    Command,
 | 
					    Command,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					impl RequestKind {
 | 
				
			||||||
 | 
					    fn name(self) -> &'static str {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Signal => "Signal",
 | 
				
			||||||
 | 
					            Self::Command => "Command",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					 | 
				
			||||||
pub struct Request<'a> {
 | 
					pub struct Request<'a> {
 | 
				
			||||||
    pub kind: RequestKind,
 | 
					    pub kind: RequestKind,
 | 
				
			||||||
    body: &'a str,
 | 
					    buffer: &'a [u8],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl std::fmt::Debug for Request<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        let mut ds = f.debug_tuple(self.kind.name());
 | 
				
			||||||
 | 
					        match self.kind {
 | 
				
			||||||
 | 
					            RequestKind::Signal => ds.field(&self.buffer),
 | 
				
			||||||
 | 
					            RequestKind::Command => match std::str::from_utf8(self.buffer) {
 | 
				
			||||||
 | 
					                Ok(str) => ds.field(&str),
 | 
				
			||||||
 | 
					                Err(_) => ds.field(&self.buffer),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ds.finish()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Request<'a> {
 | 
					impl<'a> Request<'a> {
 | 
				
			||||||
| 
						 | 
					@ -31,10 +53,9 @@ impl<'a> Request<'a> {
 | 
				
			||||||
        if char == 0x03 {
 | 
					        if char == 0x03 {
 | 
				
			||||||
            // This is how the client "cancels an in-flight request"
 | 
					            // This is how the client "cancels an in-flight request"
 | 
				
			||||||
            buffer.push(char);
 | 
					            buffer.push(char);
 | 
				
			||||||
            let body = std::str::from_utf8(buffer)?;
 | 
					 | 
				
			||||||
            return Ok(Self {
 | 
					            return Ok(Self {
 | 
				
			||||||
                kind: RequestKind::Signal,
 | 
					                kind: RequestKind::Signal,
 | 
				
			||||||
                body,
 | 
					                buffer,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if char != b'$' {
 | 
					        if char != b'$' {
 | 
				
			||||||
| 
						 | 
					@ -61,24 +82,34 @@ impl<'a> Request<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut checksum_bytes = [b'0'; 2];
 | 
					        let mut checksum_bytes = [b'0'; 2];
 | 
				
			||||||
        reader.read_exact(&mut checksum_bytes).await?;
 | 
					        reader.read_exact(&mut checksum_bytes).await?;
 | 
				
			||||||
        let checksum_str = std::str::from_utf8(&checksum_bytes)?;
 | 
					        let (real_checksum, 2) = u8::from_radix_16(&checksum_bytes) else {
 | 
				
			||||||
        let real_checksum = u8::from_str_radix(checksum_str, 16)?;
 | 
					 | 
				
			||||||
        if checksum != real_checksum {
 | 
					 | 
				
			||||||
            bail!("invalid checksum");
 | 
					            bail!("invalid checksum");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        if checksum != real_checksum {
 | 
				
			||||||
 | 
					            bail!("mismatched checksum");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let body = std::str::from_utf8(buffer)?;
 | 
					 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            kind: RequestKind::Command,
 | 
					            kind: RequestKind::Command,
 | 
				
			||||||
            body,
 | 
					            buffer,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn match_str(&mut self, prefix: &str) -> bool {
 | 
					    pub fn match_str(&mut self, prefix: &str) -> bool {
 | 
				
			||||||
        if let Some(new_body) = self.body.strip_prefix(prefix) {
 | 
					        if let Some(new_buffer) = self.buffer.strip_prefix(prefix.as_bytes()) {
 | 
				
			||||||
            self.body = new_body;
 | 
					            self.buffer = new_buffer;
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        false
 | 
					        false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn match_hex<I: FromRadix16>(&mut self) -> Option<I> {
 | 
				
			||||||
 | 
					        match I::from_radix_16(self.buffer) {
 | 
				
			||||||
 | 
					            (_, 0) => None,
 | 
				
			||||||
 | 
					            (val, used) => {
 | 
				
			||||||
 | 
					                self.buffer = self.buffer.split_at(used).1;
 | 
				
			||||||
 | 
					                Some(val)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					use num_traits::ToBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Response {
 | 
					pub struct Response {
 | 
				
			||||||
    buffer: Vec<u8>,
 | 
					    buffer: Vec<u8>,
 | 
				
			||||||
    checksum: u8,
 | 
					    checksum: u8,
 | 
				
			||||||
| 
						 | 
					@ -17,15 +19,16 @@ impl Response {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn write_str(mut self, str: &str) -> Self {
 | 
					    pub fn write_str(mut self, str: &str) -> Self {
 | 
				
			||||||
        for char in str.as_bytes() {
 | 
					        for byte in str.as_bytes() {
 | 
				
			||||||
            self.buffer.push(*char);
 | 
					            self.buffer.push(*byte);
 | 
				
			||||||
            self.checksum = self.checksum.wrapping_add(*char);
 | 
					            self.checksum = self.checksum.wrapping_add(*byte);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn write_hex_u8(mut self, value: u8) -> Self {
 | 
					    pub fn write_hex<T: ToBytes>(mut self, value: T) -> Self {
 | 
				
			||||||
        for digit in [(value >> 4), (value & 0xf)] {
 | 
					        for byte in value.to_be_bytes().as_ref() {
 | 
				
			||||||
 | 
					            for digit in [(byte >> 4), (byte & 0xf)] {
 | 
				
			||||||
                let char = if digit > 9 {
 | 
					                let char = if digit > 9 {
 | 
				
			||||||
                    b'a' + digit - 10
 | 
					                    b'a' + digit - 10
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
| 
						 | 
					@ -34,12 +37,13 @@ impl Response {
 | 
				
			||||||
                self.buffer.push(char);
 | 
					                self.buffer.push(char);
 | 
				
			||||||
                self.checksum = self.checksum.wrapping_add(char);
 | 
					                self.checksum = self.checksum.wrapping_add(char);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn finish(mut self) -> Vec<u8> {
 | 
					    pub fn finish(mut self) -> Vec<u8> {
 | 
				
			||||||
        let checksum = self.checksum;
 | 
					        let checksum = self.checksum;
 | 
				
			||||||
        self.buffer.push(b'#');
 | 
					        self.buffer.push(b'#');
 | 
				
			||||||
        self.write_hex_u8(checksum).buffer
 | 
					        self.write_hex(checksum).buffer
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue