use gdbstub::arch::Registers; use gdbstub::internal::LeBytes; use num_traits::PrimInt; /// RISC-V Integer registers. /// /// The register width is set to `u32` or `u64` based on the `` type. /// /// Useful links: /// * [GNU binutils-gdb XML descriptions](https://github.com/bminor/binutils-gdb/blob/master/gdb/features/riscv) /// * [riscv-tdep.h](https://github.com/bminor/binutils-gdb/blob/master/gdb/riscv-tdep.h) #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct RiscvCoreRegs { /// General purpose registers (x0-x31) pub x: [U; 32], /// Program counter pub pc: U, } impl Registers for RiscvCoreRegs where U: PrimInt + LeBytes + Default + core::fmt::Debug, { type ProgramCounter = U; fn pc(&self) -> Self::ProgramCounter { self.pc } fn gdb_serialize(&self, mut write_byte: impl FnMut(Option)) { macro_rules! write_le_bytes { ($value:expr) => { let mut buf = [0; 16]; // infallible (unless digit is a >128 bit number) let len = $value.to_le_bytes(&mut buf).unwrap(); let buf = &buf[..len]; for b in buf { write_byte(Some(*b)); } }; } // Write GPRs for reg in self.x.iter() { write_le_bytes!(reg); } // Program Counter is regnum 33 write_le_bytes!(&self.pc); } fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> { let ptrsize = core::mem::size_of::(); // ensure bytes.chunks_exact(ptrsize) won't panic if bytes.len() % ptrsize != 0 { return Err(()); } let mut regs = bytes .chunks_exact(ptrsize) .map(|c| U::from_le_bytes(c).unwrap()); // Read GPRs for reg in self.x.iter_mut() { *reg = regs.next().ok_or(())? } self.pc = regs.next().ok_or(())?; if regs.next().is_some() { return Err(()); } Ok(()) } }