Skip to main content

probe_rs_debug/
registers.rs

1use std::ops::Range;
2
3use probe_rs::{
4    CoreDump, CoreInterface, CoreRegister, CoreRegisters, Error, RegisterDataType, RegisterId,
5    RegisterRole, RegisterValue,
6};
7use serde::Serialize;
8
9/// Stores the relevant information from [`crate::core::CoreRegister`] for use in debug operations,
10/// as well as additional information required during debug.
11#[derive(Debug, Clone, PartialEq, Serialize)]
12pub struct DebugRegister {
13    /// To lookup platform specific details of core register definitions.
14    pub core_register: &'static CoreRegister,
15    /// [DWARF](https://dwarfstd.org) specification, section 2.6.1.1.3.1 "... operations encode the names of up to 32 registers, numbered from 0 through 31, inclusive ..."
16    pub dwarf_id: Option<u16>,
17    /// The value of the register is read from the target memory and updated as needed.
18    pub value: Option<RegisterValue>,
19}
20
21impl DebugRegister {
22    /// Test if this register role suggests that the value is a reference to an address in memory.
23    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    /// Return the memory range required to read the register value.
41    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    /// A helper function to determine if the contained register value is equal to the maximum value that can be stored in that datatype.
57    /// Will return false if the value is `None`
58    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    /// A helper function to determine if the contained register value is zero.
66    /// Will return false if the value is `None`
67    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    /// Retrieve the name of the [`CoreRegister`] role if it exists, else the name.
75    pub fn get_register_name(&self) -> String {
76        self.core_register.to_string()
77    }
78}
79
80/// All the registers required for debug related operations.
81#[derive(Debug, Clone, Default, PartialEq, Serialize)]
82pub struct DebugRegisters(pub Vec<DebugRegister>);
83
84impl DebugRegisters {
85    /// Read all registers defined in [`probe_rs::core::CoreRegisters`] from the given core.
86    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    /// Read all registers captured in the given [`CoreDump`].
103    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            // Check to ensure the register type is compatible with u64.
120            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                    // The DWARF register ID is only valid for the first 32 registers.
125                    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    /// Gets the address size for this target, in bytes
143    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    /// Wraps a program address in a [`RegisterValue`] of the target's address size, so that its
150    /// printed width is consistent across all stack frames. A plain `RegisterValue::from(u64)`
151    /// would always yield a `U64`, printing 16 hex digits on 32-bit targets.
152    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    /// Get the canonical frame address, as specified in the [DWARF](https://dwarfstd.org) specification, section 6.4.
161    /// [DWARF](https://dwarfstd.org)
162    ///
163    /// This is not always available
164    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    /// Get the program counter.
173    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    /// Get a mutable reference to the program counter.
182    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    /// Get the stack pointer.
191    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    /// Get the return address.
200    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    /// Get a register by [`RegisterId`]
209    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    /// Get a mutable reference register by [`RegisterId`]
216    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    /// Get the register value using the positional index into core registers.
223    /// [DWARF](https://dwarfstd.org) specification, section 2.6.1.1.3.1 "... operations encode the names of up to 32 registers, numbered from 0 through 31, inclusive ..."
224    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    /// Retrieve the role name if it exists, else the actual name using the [`RegisterId`] as an identifier.
231    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    /// Retrieve a reference to a register by searching against an exact match of the [`RegisterRole`].
240    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    /// Retrieve the stored value of a register by searching against an exact match of the [`RegisterRole`].
273    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    /// Retrieve a mutable reference to a register by searching against an exact match of the [`RegisterRole`].
285    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    /// Retrieve a register by searching against either the name or the role name.
298    /// Use this for registers that have platform specific names like "t1", or "s9", etc.,
299    /// and cannot efficiently be accessed through any of the other methods.
300    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}