1 use num_traits::PrimInt; 2 3 use gdbstub::arch::Registers; 4 use gdbstub::internal::LeBytes; 5 6 /// RISC-V Integer registers. 7 /// 8 /// The register width is set to `u32` or `u64` based on the `<U>` type. 9 /// 10 /// Useful links: 11 /// * [GNU binutils-gdb XML descriptions](https://github.com/bminor/binutils-gdb/blob/master/gdb/features/riscv) 12 /// * [riscv-tdep.h](https://github.com/bminor/binutils-gdb/blob/master/gdb/riscv-tdep.h) 13 #[derive(Debug, Default, Clone, PartialEq)] 14 pub struct RiscvCoreRegs<U> { 15 /// General purpose registers (x0-x31) 16 pub x: [U; 32], 17 /// Program counter 18 pub pc: U, 19 } 20 21 impl<U> Registers for RiscvCoreRegs<U> 22 where 23 U: PrimInt + LeBytes + Default + core::fmt::Debug, 24 { 25 type ProgramCounter = U; 26 pc(&self) -> Self::ProgramCounter27 fn pc(&self) -> Self::ProgramCounter { 28 self.pc 29 } 30 gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))31 fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) { 32 macro_rules! write_le_bytes { 33 ($value:expr) => { 34 let mut buf = [0; 16]; 35 // infallible (unless digit is a >128 bit number) 36 let len = $value.to_le_bytes(&mut buf).unwrap(); 37 let buf = &buf[..len]; 38 for b in buf { 39 write_byte(Some(*b)); 40 } 41 }; 42 } 43 44 // Write GPRs 45 for reg in self.x.iter() { 46 write_le_bytes!(reg); 47 } 48 49 // Program Counter is regnum 33 50 write_le_bytes!(&self.pc); 51 } 52 gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>53 fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> { 54 let ptrsize = core::mem::size_of::<U>(); 55 56 // ensure bytes.chunks_exact(ptrsize) won't panic 57 if bytes.len() % ptrsize != 0 { 58 return Err(()); 59 } 60 61 let mut regs = bytes 62 .chunks_exact(ptrsize) 63 .map(|c| U::from_le_bytes(c).unwrap()); 64 65 // Read GPRs 66 for reg in self.x.iter_mut() { 67 *reg = regs.next().ok_or(())? 68 } 69 self.pc = regs.next().ok_or(())?; 70 71 if regs.next().is_some() { 72 return Err(()); 73 } 74 75 Ok(()) 76 } 77 } 78