Skip to content

Commit

Permalink
SingleRegisterAccess: Support unavailable regs
Browse files Browse the repository at this point in the history
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 <ptosi@google.com>
  • Loading branch information
ptosi committed Jul 28, 2022
1 parent 463ab4c commit 77fb1c5
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 6 deletions.
11 changes: 10 additions & 1 deletion examples/armv4t/gdb/mod.rs
Expand Up @@ -314,6 +314,7 @@ impl target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu
);
Ok(buf.len())
}
custom_arch::ArmCoreRegIdCustom::Unavailable => Ok(0),
}
}

Expand Down Expand Up @@ -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(()),
}
}
}
Expand Down Expand Up @@ -460,13 +462,16 @@ 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 {
fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
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));
Expand Down Expand Up @@ -530,13 +535,15 @@ mod custom_arch {
ArmCoreRegIdCustom::Core(ArmCoreRegId::Fps) => "padding",
ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) => "cpsr",
ArmCoreRegIdCustom::Custom => "custom",
ArmCoreRegIdCustom::Unavailable => "Unavailable",
_ => "unknown",
};
let encoding = match r {
ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => Encoding::Uint,
ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
| ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
| ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
| ArmCoreRegIdCustom::Unavailable
| ArmCoreRegIdCustom::Custom => Encoding::Uint,
_ => Encoding::Vector,
};
Expand All @@ -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,
};
Expand All @@ -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",
};
Expand Down
8 changes: 8 additions & 0 deletions examples/armv4t/gdb/target_description_xml_override.rs
Expand Up @@ -96,5 +96,13 @@ const EXTRA_XML: &str = r#"
this register via the 'p' and 'P' packets respectively
-->
<reg name="time" bitsize="32" type="uint32"/>
<!--
pseudo-register that is always unavailable.
it is supposed to be reported as 'x'-ed bytes in replies to 'p' packets
and shown by the GDB client as "<unavailable>".
-->
<reg name="unavailable" bitsize="32" type="uint32"/>
</feature>
"#;
18 changes: 14 additions & 4 deletions src/stub/core_impl/single_register_access.rs
Expand Up @@ -33,14 +33,24 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {

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 {
for _ in 0..size.get() {
res.write_str("xx")?;
}
} 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) => {
Expand Down
3 changes: 2 additions & 1 deletion src/target/ext/base/single_register_access.rs
Expand Up @@ -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.
Expand Down

0 comments on commit 77fb1c5

Please sign in to comment.