1use core::num::NonZeroUsize;
8
9use gdbstub::arch::{Arch, RegId, Registers};
10
11#[derive(Debug, Default, Clone, PartialEq, Eq)]
13pub struct Rv32CoreRegs {
14 pub x: [u32; 32],
15 pub pc: u32,
16 pub rv32e: bool,
20}
21
22pub const RV32E_TARGET_XML: &str = concat!(
27 r#"<?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd">"#,
28 r#"<target version="1.0"><architecture>riscv:rv32</architecture>"#,
29 r#"<feature name="org.gnu.gdb.riscv.cpu">"#,
30 r#"<reg name="zero" bitsize="32" type="int" regnum="0"/>"#,
31 r#"<reg name="ra" bitsize="32" type="code_ptr"/>"#,
32 r#"<reg name="sp" bitsize="32" type="data_ptr"/>"#,
33 r#"<reg name="gp" bitsize="32" type="data_ptr"/>"#,
34 r#"<reg name="tp" bitsize="32" type="data_ptr"/>"#,
35 r#"<reg name="t0" bitsize="32" type="int"/>"#,
36 r#"<reg name="t1" bitsize="32" type="int"/>"#,
37 r#"<reg name="t2" bitsize="32" type="int"/>"#,
38 r#"<reg name="fp" bitsize="32" type="data_ptr"/>"#,
39 r#"<reg name="s1" bitsize="32" type="int"/>"#,
40 r#"<reg name="a0" bitsize="32" type="int"/>"#,
41 r#"<reg name="a1" bitsize="32" type="int"/>"#,
42 r#"<reg name="a2" bitsize="32" type="int"/>"#,
43 r#"<reg name="a3" bitsize="32" type="int"/>"#,
44 r#"<reg name="a4" bitsize="32" type="int"/>"#,
45 r#"<reg name="a5" bitsize="32" type="int"/>"#,
46 r#"<reg name="pc" bitsize="32" type="code_ptr" regnum="32"/>"#,
47 r#"</feature></target>"#,
48);
49
50impl Registers for Rv32CoreRegs {
51 type ProgramCounter = u32;
52
53 fn pc(&self) -> u32 {
54 self.pc
55 }
56
57 fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
58 let gprs = if self.rv32e { 16 } else { 32 };
59 for r in self.x[..gprs].iter().chain(core::iter::once(&self.pc)) {
60 for b in r.to_le_bytes() {
61 write_byte(Some(b));
62 }
63 }
64 }
65
66 fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
67 let gprs = if bytes.len() >= 33 * 4 {
69 32
70 } else if bytes.len() >= 17 * 4 {
71 16
72 } else {
73 return Err(());
74 };
75 self.rv32e = gprs == 16;
76 for (i, chunk) in bytes.as_chunks::<4>().0.iter().enumerate().take(gprs + 1) {
77 let v = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
78 if i < gprs {
79 self.x[i] = v;
80 } else {
81 self.pc = v;
82 }
83 }
84 Ok(())
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum Rv32RegId {
91 Gpr(u8),
92 Pc,
93}
94
95impl RegId for Rv32RegId {
96 fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
97 let size = NonZeroUsize::new(4);
98 match id {
99 0..=31 => Some((Rv32RegId::Gpr(id as u8), size)),
100 32 => Some((Rv32RegId::Pc, size)),
101 _ => None,
102 }
103 }
104
105 fn to_raw_id(&self) -> Option<usize> {
106 Some(match self {
107 Rv32RegId::Gpr(n) => *n as usize,
108 Rv32RegId::Pc => 32,
109 })
110 }
111}
112
113pub enum Rv32 {}
115
116impl Arch for Rv32 {
117 type Usize = u32;
118 type Registers = Rv32CoreRegs;
119 type BreakpointKind = usize;
120 type RegId = Rv32RegId;
121
122 fn target_description_xml() -> Option<&'static str> {
123 Some(r#"<target version="1.0"><architecture>riscv:rv32</architecture></target>"#)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 #![allow(clippy::unwrap_used)]
131 use super::*;
132
133 #[test]
134 fn core_regs_serialize_roundtrip() {
135 let mut regs = Rv32CoreRegs::default();
136 for (i, x) in regs.x.iter_mut().enumerate() {
137 *x = 0x1000_0000 + i as u32;
138 }
139 regs.pc = 0x0800_0000;
140
141 let mut bytes = Vec::new();
143 regs.gdb_serialize(|b| {
144 if let Some(b) = b {
145 bytes.push(b);
146 }
147 });
148 assert_eq!(bytes.len(), 33 * 4);
149 assert_eq!(&bytes[0..4], &0x1000_0000u32.to_le_bytes()); assert_eq!(&bytes[128..132], &0x0800_0000u32.to_le_bytes()); let mut back = Rv32CoreRegs::default();
154 back.gdb_deserialize(&bytes).unwrap();
155 assert_eq!(back, regs);
156 }
157
158 #[test]
159 fn deserialize_rejects_short_input() {
160 let mut regs = Rv32CoreRegs::default();
161 assert!(regs.gdb_deserialize(&[0u8; 67]).is_err());
162 }
163
164 #[test]
165 fn rv32e_has_16_gprs_and_pc() {
166 let mut regs = Rv32CoreRegs {
167 rv32e: true,
168 pc: 0x3cc,
169 ..Default::default()
170 };
171 regs.x[15] = 0xf;
172 let mut bytes = Vec::new();
173 regs.gdb_serialize(|b| bytes.extend(b));
174 assert_eq!(bytes.len(), 17 * 4);
175 assert_eq!(&bytes[60..64], &0xfu32.to_le_bytes()); assert_eq!(&bytes[64..68], &0x3ccu32.to_le_bytes()); let mut back = Rv32CoreRegs::default();
178 back.gdb_deserialize(&bytes).unwrap();
179 assert_eq!(back, regs);
180 }
181
182 #[test]
183 fn reg_id_mapping() {
184 assert_eq!(
185 Rv32RegId::from_raw_id(0).map(|(r, _)| r),
186 Some(Rv32RegId::Gpr(0))
187 );
188 assert_eq!(
189 Rv32RegId::from_raw_id(31).map(|(r, _)| r),
190 Some(Rv32RegId::Gpr(31))
191 );
192 assert_eq!(
193 Rv32RegId::from_raw_id(32).map(|(r, _)| r),
194 Some(Rv32RegId::Pc)
195 );
196 assert!(Rv32RegId::from_raw_id(33).is_none());
197 }
198}