From de46637dd44a64ddf779b36820a0580f9b70ecc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Cl=C3=A9ment=20Tosi?= Date: Wed, 20 Jul 2022 19:45:06 +0100 Subject: [PATCH] SingleRegisterAccess: Support unavailable regs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable an implementation of SingleRegisterAccess to signal to gdbstub that a read register is recognized (as per RegId::from_raw_id()) but is unavailable by reporting a 0-byte read. In that case, make gdbstub report to the GDB client the state of the unavailable register by following the registers packet protocol: > [...] the stub may also return a string of literal `x`s in place of > the register data digits, to indicate that the corresponding register > has not been collected, thus its value is unavailable. Signed-off-by: Pierre-Clément Tosi --- examples/armv4t/gdb/mod.rs | 11 ++++++++++- .../gdb/target_description_xml_override.rs | 8 ++++++++ src/stub/core_impl/single_register_access.rs | 16 ++++++++++++---- src/target/ext/base/single_register_access.rs | 3 ++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/examples/armv4t/gdb/mod.rs b/examples/armv4t/gdb/mod.rs index 08315664..97f7b2de 100644 --- a/examples/armv4t/gdb/mod.rs +++ b/examples/armv4t/gdb/mod.rs @@ -314,6 +314,7 @@ impl target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu ); Ok(buf.len()) } + custom_arch::ArmCoreRegIdCustom::Unavailable => Ok(0), } } @@ -341,7 +342,8 @@ impl target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu Ok(()) } // ignore writes - custom_arch::ArmCoreRegIdCustom::Time => Ok(()), + custom_arch::ArmCoreRegIdCustom::Unavailable + | custom_arch::ArmCoreRegIdCustom::Time => Ok(()), } } } @@ -460,6 +462,8 @@ mod custom_arch { // not sent as part of `struct ArmCoreRegsCustom`, and only accessible via the single // register read/write functions Time, + /// This pseudo-register is valid but never available + Unavailable, } impl RegId for ArmCoreRegIdCustom { @@ -467,6 +471,7 @@ mod custom_arch { let reg = match id { 26 => Self::Custom, 27 => Self::Time, + 28 => Self::Unavailable, _ => { let (reg, size) = ArmCoreRegId::from_raw_id(id)?; return Some((Self::Core(reg), size)); @@ -530,6 +535,7 @@ mod custom_arch { ArmCoreRegIdCustom::Core(ArmCoreRegId::Fps) => "padding", ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) => "cpsr", ArmCoreRegIdCustom::Custom => "custom", + ArmCoreRegIdCustom::Unavailable => "Unavailable", _ => "unknown", }; let encoding = match r { @@ -537,6 +543,7 @@ mod custom_arch { ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) + | ArmCoreRegIdCustom::Unavailable | ArmCoreRegIdCustom::Custom => Encoding::Uint, _ => Encoding::Vector, }; @@ -545,6 +552,7 @@ mod custom_arch { ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) + | ArmCoreRegIdCustom::Unavailable | ArmCoreRegIdCustom::Custom => Format::Hex, _ => Format::VectorUInt8, }; @@ -555,6 +563,7 @@ mod custom_arch { ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) + | ArmCoreRegIdCustom::Unavailable | ArmCoreRegIdCustom::Custom => "General Purpose Registers", _ => "Floating Point Registers", }; diff --git a/examples/armv4t/gdb/target_description_xml_override.rs b/examples/armv4t/gdb/target_description_xml_override.rs index 294b5139..2c5348c3 100644 --- a/examples/armv4t/gdb/target_description_xml_override.rs +++ b/examples/armv4t/gdb/target_description_xml_override.rs @@ -96,5 +96,13 @@ const EXTRA_XML: &str = r#" this register via the 'p' and 'P' packets respectively --> + + + "#; diff --git a/src/stub/core_impl/single_register_access.rs b/src/stub/core_impl/single_register_access.rs index fd61c585..cace9d6d 100644 --- a/src/stub/core_impl/single_register_access.rs +++ b/src/stub/core_impl/single_register_access.rs @@ -33,14 +33,22 @@ impl GdbStubImpl { let len = ops.read_register(id, reg_id, buf).handle_error()?; - if let Some(size) = reg_size { - if size.get() != len { + if len == 0 { + if let Some(size) = reg_size { + res.write_x(size.get())?; + } else { return Err(Error::TargetMismatch); } } else { - buf = buf.get_mut(..len).ok_or(Error::PacketBufferOverflow)?; + if let Some(size) = reg_size { + if size.get() != len { + return Err(Error::TargetMismatch); + } + } else { + buf = buf.get_mut(..len).ok_or(Error::PacketBufferOverflow)?; + } + res.write_hex_buf(buf)?; } - res.write_hex_buf(buf)?; HandlerStatus::Handled } SingleRegisterAccess::P(p) => { diff --git a/src/target/ext/base/single_register_access.rs b/src/target/ext/base/single_register_access.rs index f7a9b16a..2887feff 100644 --- a/src/target/ext/base/single_register_access.rs +++ b/src/target/ext/base/single_register_access.rs @@ -29,7 +29,8 @@ where /// Implementations should write the value of the register using target's /// native byte order in the buffer `buf`. /// - /// Return the number of bytes written into `buf`. + /// Return the number of bytes written into `buf` or `0` if the register is + /// valid but unavailable. /// /// If the requested register could not be accessed, an appropriate /// non-fatal error should be returned.