From a28791aa0198b7dfb7b460e68f602f4eeaf0f4ac Mon Sep 17 00:00:00 2001 From: Thomas Scholtes Date: Thu, 27 Oct 2022 11:32:44 +0200 Subject: [PATCH] `read_addrs()` can return fewer bytes than requested The `read_addrs()` method for targets now returns a number of bytes that were read. This allows a target to gracefully signal the client that memory at an address range is not accessible. Signed-off-by: Thomas Scholtes --- example_no_std/src/gdb.rs | 4 ++-- examples/armv4t/gdb/mod.rs | 17 ++++++++++++++--- examples/armv4t_multicore/gdb.rs | 4 ++-- src/stub/core_impl/base.rs | 4 +++- src/target/ext/base/multithread.rs | 18 +++++++++++++----- src/target/ext/base/singlethread.rs | 18 +++++++++++++----- src/target/mod.rs | 4 ++-- 7 files changed, 49 insertions(+), 20 deletions(-) diff --git a/example_no_std/src/gdb.rs b/example_no_std/src/gdb.rs index ea6612b6..976664c2 100644 --- a/example_no_std/src/gdb.rs +++ b/example_no_std/src/gdb.rs @@ -71,10 +71,10 @@ impl MultiThreadBase for DummyTarget { _start_addr: u32, data: &mut [u8], _tid: Tid, // same address space for each core - ) -> TargetResult<(), Self> { + ) -> TargetResult { print_str("> read_addrs"); data.iter_mut().for_each(|b| *b = 0x55); - Ok(()) + Ok(data.len()) } #[inline(never)] diff --git a/examples/armv4t/gdb/mod.rs b/examples/armv4t/gdb/mod.rs index 97f7b2de..5df6b10f 100644 --- a/examples/armv4t/gdb/mod.rs +++ b/examples/armv4t/gdb/mod.rs @@ -196,11 +196,22 @@ impl SingleThreadBase for Emu { Some(self) } - fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<(), Self> { - for (addr, val) in (start_addr..).zip(data.iter_mut()) { + fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult { + // These values are taken from the link script. + const MEMORY_ORIGIN: u32 = 0x5555_0000; + const MEMORY_LENGTH: u32 = 0x1000_0000; + const MEMORY_END: u32 = MEMORY_ORIGIN + MEMORY_LENGTH; + + if !(MEMORY_ORIGIN..MEMORY_END).contains(&start_addr) { + return Err(TargetError::NonFatal); + } + + let end_addr = std::cmp::min(start_addr + data.len() as u32, MEMORY_END); + + for (addr, val) in (start_addr..end_addr).zip(data.iter_mut()) { *val = self.mem.r8(addr) } - Ok(()) + Ok((end_addr - start_addr) as usize) } fn write_addrs(&mut self, start_addr: u32, data: &[u8]) -> TargetResult<(), Self> { diff --git a/examples/armv4t_multicore/gdb.rs b/examples/armv4t_multicore/gdb.rs index 3c8cd75a..2ad14627 100644 --- a/examples/armv4t_multicore/gdb.rs +++ b/examples/armv4t_multicore/gdb.rs @@ -92,11 +92,11 @@ impl MultiThreadBase for Emu { start_addr: u32, data: &mut [u8], _tid: Tid, // same address space for each core - ) -> TargetResult<(), Self> { + ) -> TargetResult { for (addr, val) in (start_addr..).zip(data.iter_mut()) { *val = self.mem.r8(addr) } - Ok(()) + Ok(data.len()) } fn write_addrs( diff --git a/src/stub/core_impl/base.rs b/src/stub/core_impl/base.rs index c0df01a7..771dc086 100644 --- a/src/stub/core_impl/base.rs +++ b/src/stub/core_impl/base.rs @@ -238,7 +238,7 @@ impl GdbStubImpl { let addr = addr + NumCast::from(i).ok_or(Error::TargetMismatch)?; let data = &mut buf[..chunk_size]; - match target.base_ops() { + let data_len = match target.base_ops() { BaseOps::SingleThread(ops) => ops.read_addrs(addr, data), BaseOps::MultiThread(ops) => { ops.read_addrs(addr, data, self.current_mem_tid) @@ -249,6 +249,8 @@ impl GdbStubImpl { n -= chunk_size; i += chunk_size; + // TODO: add more specific error variant? + let data = data.get(..data_len).ok_or(Error::PacketBufferOverflow)?; res.write_hex_buf(data)?; } HandlerStatus::Handled diff --git a/src/target/ext/base/multithread.rs b/src/target/ext/base/multithread.rs index 693030ef..4b993eb2 100644 --- a/src/target/ext/base/multithread.rs +++ b/src/target/ext/base/multithread.rs @@ -43,17 +43,25 @@ pub trait MultiThreadBase: Target { None } - /// Read bytes from the specified address range. + /// Read bytes from the specified address range and return the number of + /// bytes that were read. /// - /// If the requested address range could not be accessed (e.g: due to - /// MMU protection, unhanded page fault, etc...), an appropriate non-fatal - /// error should be returned. + /// Implementations may return a number `n` that is less than `data.len()` + /// to indicate that memory starting at `start_addr + n` cannot be + /// accessed. + /// + /// Implemenations may also return an appropriate non-fatal if the requested + /// address range could not be accessed (e.g: due to MMU protection, + /// unhanded page fault, etc...). + /// + /// Implementations must guarantee that the returned number is less than or + /// equal `data.len()`. fn read_addrs( &mut self, start_addr: ::Usize, data: &mut [u8], tid: Tid, - ) -> TargetResult<(), Self>; + ) -> TargetResult; /// Write bytes to the specified address range. /// diff --git a/src/target/ext/base/singlethread.rs b/src/target/ext/base/singlethread.rs index c9498867..1da17053 100644 --- a/src/target/ext/base/singlethread.rs +++ b/src/target/ext/base/singlethread.rs @@ -32,16 +32,24 @@ pub trait SingleThreadBase: Target { None } - /// Read bytes from the specified address range. + /// Read bytes from the specified address range and return the number of + /// bytes that were read. /// - /// If the requested address range could not be accessed (e.g: due to - /// MMU protection, unhanded page fault, etc...), an appropriate - /// non-fatal error should be returned. + /// Implementations may return a number `n` that is less than `data.len()` + /// to indicate that memory starting at `start_addr + n` cannot be + /// accessed. + /// + /// Implemenations may also return an appropriate non-fatal error if the + /// requested address range could not be accessed (e.g: due to MMU + /// protection, unhanded page fault, etc...). + /// + /// Implementations must guarantee that the returned number is less than or + /// equal `data.len()`. fn read_addrs( &mut self, start_addr: ::Usize, data: &mut [u8], - ) -> TargetResult<(), Self>; + ) -> TargetResult; /// Write bytes to the specified address range. /// diff --git a/src/target/mod.rs b/src/target/mod.rs index a5d912b6..491264e2 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -151,7 +151,7 @@ //! &mut self, //! start_addr: u32, //! data: &mut [u8], -//! ) -> TargetResult<(), Self> { todo!() } +//! ) -> TargetResult { todo!() } //! //! fn write_addrs( //! &mut self, @@ -409,7 +409,7 @@ pub trait Target { /// # &mut self, /// # start_addr: u32, /// # data: &mut [u8], - /// # ) -> TargetResult<(), Self> { todo!() } + /// # ) -> TargetResult { todo!() } /// # /// # fn write_addrs( /// # &mut self,