probe_rs_debug/
registers.rs1use std::ops::Range;
2
3use probe_rs::{
4 CoreDump, CoreInterface, CoreRegister, CoreRegisters, Error, RegisterDataType, RegisterId,
5 RegisterRole, RegisterValue,
6};
7use serde::Serialize;
8
9#[derive(Debug, Clone, PartialEq, Serialize)]
12pub struct DebugRegister {
13 pub core_register: &'static CoreRegister,
15 pub dwarf_id: Option<u16>,
17 pub value: Option<RegisterValue>,
19}
20
21impl DebugRegister {
22 pub(crate) fn is_pointer(&self) -> bool {
24 for role in self.core_register.roles.iter() {
25 if matches!(
26 role,
27 RegisterRole::ProgramCounter
28 | RegisterRole::FramePointer
29 | RegisterRole::StackPointer
30 | RegisterRole::ReturnAddress
31 | RegisterRole::MainStackPointer
32 | RegisterRole::ProcessStackPointer
33 ) {
34 return true;
35 }
36 }
37 false
38 }
39
40 pub fn memory_range(&self) -> Result<Option<Range<u64>>, Error> {
42 if self.is_pointer()
43 && let Some(mut register_value) = self.value
44 {
45 let start_address: u64 = register_value.try_into()?;
46 register_value.increment_address(self.core_register.size_in_bytes())?;
47 let end_address: u64 = register_value.try_into()?;
48 return Ok(Some(Range {
49 start: start_address,
50 end: end_address,
51 }));
52 }
53 Ok(None)
54 }
55
56 pub(crate) fn is_max_value(&self) -> bool {
59 match self.value {
60 Some(register_value) => register_value.is_max_value(),
61 None => false,
62 }
63 }
64
65 pub(crate) fn is_zero(&self) -> bool {
68 match self.value {
69 Some(register_value) => register_value.is_zero(),
70 None => false,
71 }
72 }
73
74 pub fn get_register_name(&self) -> String {
76 self.core_register.to_string()
77 }
78}
79
80#[derive(Debug, Clone, Default, PartialEq, Serialize)]
82pub struct DebugRegisters(pub Vec<DebugRegister>);
83
84impl DebugRegisters {
85 pub fn from_core(core: &mut impl CoreInterface) -> Self {
87 if let Err(error) = core.spill_registers() {
88 tracing::warn!("Failed to spill registers: {error}");
89 };
90 Self::from_core_registers(core.registers(), |register_id| {
91 core.read_core_reg(*register_id)
92 .inspect_err(|error| {
93 tracing::warn!(
94 "Failed to read value for register {:?}: {error}",
95 register_id
96 )
97 })
98 .ok()
99 })
100 }
101
102 pub fn from_coredump(core: &CoreDump) -> Self {
104 Self::from_core_registers(core.registers(), |register_id| {
105 let value = core.registers.get(register_id).cloned();
106 if value.is_none() {
107 tracing::warn!("Failed to read value for register {:?}", register_id);
108 }
109 value
110 })
111 }
112
113 fn from_core_registers(
114 regs: &'static CoreRegisters,
115 mut reg_value: impl FnMut(&RegisterId) -> Option<RegisterValue>,
116 ) -> Self {
117 let mut debug_registers = Vec::<DebugRegister>::new();
118 for (dwarf_id, core_register) in regs.core_registers().enumerate() {
119 if matches!(core_register.data_type(), RegisterDataType::UnsignedInteger(size_in_bits) if size_in_bits <= 64)
121 {
122 debug_registers.push(DebugRegister {
123 core_register,
124 dwarf_id: if dwarf_id < 32 {
126 Some(dwarf_id as u16)
127 } else {
128 None
129 },
130 value: reg_value(&core_register.id()),
131 });
132 } else {
133 tracing::trace!(
134 "Unwind will use the default rule for this register : {:?}",
135 core_register
136 );
137 }
138 }
139 DebugRegisters(debug_registers)
140 }
141
142 pub fn get_address_size_bytes(&self) -> usize {
144 self.get_program_counter()
145 .map(|debug_register| debug_register.core_register.size_in_bits().div_ceil(8))
146 .unwrap_or(0)
147 }
148
149 pub fn address_to_register_value(&self, address: u64) -> RegisterValue {
153 match self.get_address_size_bytes() {
154 4 => RegisterValue::U32(address as u32),
155 8 => RegisterValue::U64(address),
156 _ => RegisterValue::from(address),
157 }
158 }
159
160 pub fn get_frame_pointer(&self) -> Option<&DebugRegister> {
165 self.0.iter().find(|debug_register| {
166 debug_register
167 .core_register
168 .register_has_role(RegisterRole::FramePointer)
169 })
170 }
171
172 pub fn get_program_counter<'b, 'c: 'b>(&'c self) -> Option<&'b DebugRegister> {
174 self.0.iter().find(|debug_register| {
175 debug_register
176 .core_register
177 .register_has_role(RegisterRole::ProgramCounter)
178 })
179 }
180
181 pub fn get_program_counter_mut<'b, 'c: 'b>(&'c mut self) -> Option<&'b mut DebugRegister> {
183 self.0.iter_mut().find(|debug_register| {
184 debug_register
185 .core_register
186 .register_has_role(RegisterRole::ProgramCounter)
187 })
188 }
189
190 pub fn get_stack_pointer(&self) -> Option<&DebugRegister> {
192 self.0.iter().find(|debug_register| {
193 debug_register
194 .core_register
195 .register_has_role(RegisterRole::StackPointer)
196 })
197 }
198
199 pub fn get_return_address(&self) -> Option<&DebugRegister> {
201 self.0.iter().find(|debug_register| {
202 debug_register
203 .core_register
204 .register_has_role(RegisterRole::ReturnAddress)
205 })
206 }
207
208 pub fn get_register(&self, register_id: RegisterId) -> Option<&DebugRegister> {
210 self.0
211 .iter()
212 .find(|debug_register| debug_register.core_register.id == register_id)
213 }
214
215 pub fn get_register_mut(&mut self, register_id: RegisterId) -> Option<&mut DebugRegister> {
217 self.0
218 .iter_mut()
219 .find(|debug_register| debug_register.core_register.id == register_id)
220 }
221
222 pub fn get_register_by_dwarf_id(&self, dwarf_id: u16) -> Option<&DebugRegister> {
225 self.0
226 .iter()
227 .find(|debug_register| debug_register.dwarf_id == Some(dwarf_id))
228 }
229
230 pub fn get_register_name(&self, register_id: RegisterId) -> String {
232 self.0
233 .iter()
234 .find(|debug_register| debug_register.core_register.id == register_id)
235 .map(|debug_register| debug_register.get_register_name())
236 .unwrap_or_else(|| "unknown register".to_string())
237 }
238
239 pub fn get_register_by_role(
241 &self,
242 register_role: &RegisterRole,
243 ) -> Result<&DebugRegister, Error> {
244 let qualifying_registers = self
245 .0
246 .iter()
247 .filter(|debug_register| {
248 debug_register
249 .core_register
250 .roles
251 .iter()
252 .any(|role| role == register_role)
253 })
254 .collect::<Vec<&DebugRegister>>();
255 if qualifying_registers.is_empty() {
256 Err(Error::Register(format!(
257 "No {register_role:?} registers. Please report this as a bug."
258 )))
259 } else if qualifying_registers.len() == 1 {
260 qualifying_registers.first().cloned().ok_or_else(|| {
261 Error::Register(format!(
262 "No {register_role:?} registers. Please report this as a bug."
263 ))
264 })
265 } else {
266 Err(Error::Register(format!(
267 "Multiple {register_role:?} registers. Please report this as a bug."
268 )))
269 }
270 }
271
272 pub fn get_register_value_by_role(&self, register_role: &RegisterRole) -> Result<u64, Error> {
274 self.get_register_by_role(register_role)?
275 .value
276 .ok_or_else(|| {
277 Error::Register(format!(
278 "No value for {register_role:?} register. Please report this as a bug."
279 ))
280 })?
281 .try_into()
282 }
283
284 pub fn get_register_mut_by_role(
286 &mut self,
287 register_role: &RegisterRole,
288 ) -> Result<&mut DebugRegister, Error> {
289 self.get_register_mut(self.get_register_by_role(register_role)?.core_register.id)
290 .ok_or_else(|| {
291 Error::Register(format!(
292 "No {register_role:?} registers. Please report this as a bug."
293 ))
294 })
295 }
296
297 pub fn get_register_by_name(&self, register_name: &str) -> Option<DebugRegister> {
301 self.0
302 .iter()
303 .find(|&debug_register| {
304 for role in debug_register.core_register.roles {
305 if matches!(role, RegisterRole::Core(role_name) | RegisterRole::Argument(role_name) | RegisterRole::Return(role_name) | RegisterRole::Other(role_name) if *role_name == register_name) {
306 return true;
307 }
308 }
309 false
310 })
311 .cloned()
312 }
313}