probe_rs/core/
registers.rs

1//! Core registers are represented by the `CoreRegister` struct, and collected in a `RegisterFile` for each of the supported architectures.
2
3use crate::Error;
4use serde::{Deserialize, Serialize};
5use std::{
6    cmp::Ordering,
7    convert::Infallible,
8    fmt::{Display, Formatter},
9};
10
11/// The type of data stored in a register, with size in bits encapsulated in the enum.
12#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
13pub enum RegisterDataType {
14    /// Unsigned integer data, with size in bits encapsulated.
15    UnsignedInteger(usize),
16    /// Floating point data, with size in bits encapsulated.
17    FloatingPoint(usize),
18}
19
20/// This is used to label the register with a specific role that it plays during program execution and exception handling.
21/// This denotes the purpose of a register (e.g. `return address`),
22/// while the [`CoreRegister::name`] will contain the architecture specific label of the register.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
24pub enum RegisterRole {
25    /// The default role for a register, with the name as defined by the architecture.
26    Core(&'static str),
27    /// Function Argument registers like "A0", "a1", etc. (uses architecture specific names)
28    Argument(&'static str),
29    /// Function Return value registers like "R0", "r1", etc. (uses architecture specific names)
30    Return(&'static str),
31    /// Program Counter register
32    ProgramCounter,
33    /// Frame Pointer register
34    FramePointer,
35    /// Stack Pointer register
36    StackPointer,
37    /// Main Stack Pointer register
38    MainStackPointer,
39    /// Process Stack Pointer register
40    ProcessStackPointer,
41    /// Processor Status register
42    ProcessorStatus,
43    /// Return Address register
44    ReturnAddress,
45    /// Floating Point Unit register
46    FloatingPoint,
47    /// Floating Point Status register
48    FloatingPointStatus,
49    /// Other architecture specific roles, e.g. "saved", "temporary", "variable", etc.
50    Other(&'static str),
51}
52
53impl Display for RegisterRole {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        match self {
56            RegisterRole::Core(name) => write!(f, "{}", name),
57            RegisterRole::Argument(name) => write!(f, "{}", name),
58            RegisterRole::Return(name) => write!(f, "{}", name),
59            RegisterRole::ProgramCounter => write!(f, "PC"),
60            RegisterRole::FramePointer => write!(f, "FP"),
61            RegisterRole::StackPointer => write!(f, "SP"),
62            RegisterRole::MainStackPointer => write!(f, "MSP"),
63            RegisterRole::ProcessStackPointer => write!(f, "PSP"),
64            RegisterRole::ProcessorStatus => write!(f, "PSR"),
65            RegisterRole::ReturnAddress => write!(f, "LR"),
66            RegisterRole::FloatingPoint => write!(f, "FPU"),
67            RegisterRole::FloatingPointStatus => write!(f, "FPSR"),
68            RegisterRole::Other(name) => write!(f, "{}", name),
69        }
70    }
71}
72
73/// The rule used to preserve the value of a register between function calls during unwinding,
74/// when DWARF unwind information is not available.
75///
76/// The rules for these are based on the 'Procedure Calling Standard' for each of the supported architectures:
77/// - Implemented: [AAPCS32](https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#core-registers)
78/// - To be Implemented: [AAPCS64](https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#core-registers)
79/// - To be Implemented: [RISC-V PCS](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf)
80///
81/// Please note that the `Procedure Calling Standard` define register rules for the act of calling and/or returning from functions,
82/// while the timing of a stack unwinding is different (the `callee` has not yet completed / executed the epilogue),
83/// and the rules about preserving register values have to take this into account.
84#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
85pub enum UnwindRule {
86    /// Callee-saved, a.k.a non-volatile registers, or call-preserved.
87    /// If there is DWARF unwind `RegisterRule` we will apply it during unwind,
88    /// otherwise we assume it was untouched and preserve the current value.
89    Preserve,
90    /// Caller-saved, a.k.a. volatile registers, or call-clobbered.
91    /// If there is DWARF unwind `RegisterRule` we will apply it during unwind,
92    /// otherwise we assume it was corrupted by the callee, and clear the value.
93    /// Note: This is the default value, and is used for all situations where DWARF unwind
94    /// information is not available, and the register is not explicitly marked in the definition.
95    #[default]
96    Clear,
97    /// Additional rules are required to determine the value of the register.
98    /// These are typically found in either the DWARF unwind information,
99    /// or requires additional platform specific registers to be read.
100    SpecialRule,
101}
102
103/// Describes a core (or CPU / hardware) register with its properties.
104/// Each architecture will have a set of general purpose registers, and potentially some special purpose registers. It also happens that some general purpose registers can be used for special purposes. For instance, some ARM variants allows the `LR` (link register / return address) to be used as general purpose register `R14`."
105#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
106pub struct CoreRegister {
107    /// Some architectures have multiple names for the same register, depending on the context and the role of the register.
108    pub id: RegisterId,
109    /// If the register plays a special role (one or more) during program execution and exception handling, this array will contain the appropriate [`RegisterRole`] entry/entries.
110    pub roles: &'static [RegisterRole],
111    /// The data type of the register
112    pub data_type: RegisterDataType,
113    /// For unwind purposes (debug and/or exception handling), we need to know how values are preserved between function calls. (Applies to ARM and RISC-V)
114    #[serde(skip_serializing)]
115    pub unwind_rule: UnwindRule,
116}
117
118impl PartialOrd for CoreRegister {
119    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
120        Some(self.id.cmp(&other.id))
121    }
122}
123
124impl Ord for CoreRegister {
125    fn cmp(&self, other: &Self) -> Ordering {
126        self.id.cmp(&other.id)
127    }
128}
129
130impl Display for CoreRegister {
131    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132        let primary_name = self.name();
133        write!(f, "{}", primary_name)?;
134        if !self.roles.is_empty() {
135            for role in self.roles {
136                if primary_name != role.to_string() {
137                    write!(f, "/{}", role)?;
138                }
139            }
140        }
141        Ok(())
142    }
143}
144
145impl CoreRegister {
146    /// Get the primary display name (As defined by `RegisterRole::Core()` of this register
147    pub fn name(&self) -> &'static str {
148        self.roles
149            .iter()
150            .find_map(|role| match role {
151                RegisterRole::Core(name) => Some(*name),
152                _ => None,
153            })
154            .unwrap_or("Unknown")
155    }
156
157    /// Get the id of this register
158    pub fn id(&self) -> RegisterId {
159        self.id
160    }
161
162    /// Get the type of data stored in this register
163    pub fn data_type(&self) -> RegisterDataType {
164        self.data_type.clone()
165    }
166
167    /// Get the size, in bits, of this register
168    pub fn size_in_bits(&self) -> usize {
169        match self.data_type() {
170            RegisterDataType::UnsignedInteger(size_in_bits) => size_in_bits,
171            RegisterDataType::FloatingPoint(size_in_bits) => size_in_bits,
172        }
173    }
174
175    /// Get the size, in bytes, of this register
176    pub fn size_in_bytes(&self) -> usize {
177        // Always round up
178        self.size_in_bits().div_ceil(8)
179    }
180
181    /// Get the width to format this register as a hex string
182    /// Assumes a format string like `{:#0<width>x}`
183    pub fn format_hex_width(&self) -> usize {
184        (self.size_in_bytes() * 2) + 2
185    }
186
187    /// Helper method to identify registers that have a specific role in its definition.
188    pub fn register_has_role(&self, role: RegisterRole) -> bool {
189        for r in self.roles {
190            if r == &role {
191                return true;
192            }
193        }
194        false
195    }
196}
197
198impl From<CoreRegister> for RegisterId {
199    fn from(description: CoreRegister) -> RegisterId {
200        description.id
201    }
202}
203
204impl From<&CoreRegister> for RegisterId {
205    fn from(description: &CoreRegister) -> RegisterId {
206        description.id
207    }
208}
209
210/// The location of a CPU \register. This is not an actual memory address, but a core specific location that represents a specific core register.
211#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
212#[serde(transparent)]
213pub struct RegisterId(pub u16);
214
215impl From<RegisterId> for u32 {
216    fn from(value: RegisterId) -> Self {
217        u32::from(value.0)
218    }
219}
220
221impl From<u16> for RegisterId {
222    fn from(value: u16) -> Self {
223        RegisterId(value)
224    }
225}
226
227/// A value of a core register
228///
229/// Creating a new `RegisterValue` should be done using From or Into.
230/// Converting a value back to a primitive type can be done with either
231/// a match arm or TryInto
232#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
233pub enum RegisterValue {
234    /// 32-bit unsigned integer
235    U32(u32),
236    /// 64-bit unsigned integer
237    U64(u64),
238    /// 128-bit unsigned integer, often used with SIMD / FP
239    U128(u128),
240}
241
242impl RegisterValue {
243    /// Safely increment an address by a fixed number of bytes.
244    pub fn increment_address(&mut self, bytes: usize) -> Result<(), Error> {
245        match self {
246            RegisterValue::U32(value) => {
247                if let Some(reg_val) = value.checked_add(bytes as u32) {
248                    *value = reg_val;
249                    Ok(())
250                } else {
251                    Err(Error::Other(format!(
252                        "Overflow error: Attempting to add {} bytes to Register value {}",
253                        bytes, self
254                    )))
255                }
256            }
257            RegisterValue::U64(value) => {
258                if let Some(reg_val) = value.checked_add(bytes as u64) {
259                    *value = reg_val;
260                    Ok(())
261                } else {
262                    Err(Error::Other(format!(
263                        "Overflow error: Attempting to add {} bytes to Register value {}",
264                        bytes, self
265                    )))
266                }
267            }
268            RegisterValue::U128(value) => {
269                if let Some(reg_val) = value.checked_add(bytes as u128) {
270                    *value = reg_val;
271                    Ok(())
272                } else {
273                    Err(Error::Other(format!(
274                        "Overflow error: Attempting to add {} bytes to Register value {}",
275                        bytes, self
276                    )))
277                }
278            }
279        }
280    }
281
282    /// Safely decrement an address by a fixed number of bytes.
283    pub fn decrement_address(&mut self, bytes: usize) -> Result<(), Error> {
284        match self {
285            RegisterValue::U32(value) => {
286                if let Some(reg_val) = value.checked_sub(bytes as u32) {
287                    *value = reg_val;
288                    Ok(())
289                } else {
290                    Err(Error::Other(format!(
291                        "Overflow error: Attempting to subtract {} bytes to Register value {}",
292                        bytes, self
293                    )))
294                }
295            }
296            RegisterValue::U64(value) => {
297                if let Some(reg_val) = value.checked_sub(bytes as u64) {
298                    *value = reg_val;
299                    Ok(())
300                } else {
301                    Err(Error::Other(format!(
302                        "Overflow error: Attempting to subtract {} bytes to Register value {}",
303                        bytes, self
304                    )))
305                }
306            }
307            RegisterValue::U128(value) => {
308                if let Some(reg_val) = value.checked_sub(bytes as u128) {
309                    *value = reg_val;
310                    Ok(())
311                } else {
312                    Err(Error::Other(format!(
313                        "Overflow error: Attempting to subtract {} bytes to Register value {}",
314                        bytes, self
315                    )))
316                }
317            }
318        }
319    }
320
321    /// Determine if the contained register value is equal to the maximum value that can be stored in that datatype.
322    pub fn is_max_value(&self) -> bool {
323        match self {
324            RegisterValue::U32(register_value) => *register_value == u32::MAX,
325            RegisterValue::U64(register_value) => *register_value == u64::MAX,
326            RegisterValue::U128(register_value) => *register_value == u128::MAX,
327        }
328    }
329
330    /// Determine if the contained register value is zero.
331    pub fn is_zero(&self) -> bool {
332        matches!(
333            self,
334            RegisterValue::U32(0) | RegisterValue::U64(0) | RegisterValue::U128(0)
335        )
336    }
337}
338
339impl Default for RegisterValue {
340    fn default() -> Self {
341        // Smallest data storage as default.
342        RegisterValue::U32(0_u32)
343    }
344}
345
346impl PartialOrd for RegisterValue {
347    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
348        let self_value = match self {
349            RegisterValue::U32(self_value) => *self_value as u128,
350            RegisterValue::U64(self_value) => *self_value as u128,
351            RegisterValue::U128(self_value) => *self_value,
352        };
353        let other_value = match other {
354            RegisterValue::U32(other_value) => *other_value as u128,
355            RegisterValue::U64(other_value) => *other_value as u128,
356            RegisterValue::U128(other_value) => *other_value,
357        };
358        self_value.partial_cmp(&other_value)
359    }
360}
361
362impl PartialEq for RegisterValue {
363    fn eq(&self, other: &Self) -> bool {
364        let self_value = match self {
365            RegisterValue::U32(self_value) => *self_value as u128,
366            RegisterValue::U64(self_value) => *self_value as u128,
367            RegisterValue::U128(self_value) => *self_value,
368        };
369        let other_value = match other {
370            RegisterValue::U32(other_value) => *other_value as u128,
371            RegisterValue::U64(other_value) => *other_value as u128,
372            RegisterValue::U128(other_value) => *other_value,
373        };
374        self_value == other_value
375    }
376}
377
378impl core::fmt::Display for RegisterValue {
379    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
380        match self {
381            RegisterValue::U32(register_value) => write!(f, "{register_value:#010x}"),
382            RegisterValue::U64(register_value) => write!(f, "{register_value:#018x}"),
383            RegisterValue::U128(register_value) => write!(f, "{register_value:#034x}"),
384        }
385    }
386}
387
388impl From<u32> for RegisterValue {
389    fn from(val: u32) -> Self {
390        Self::U32(val)
391    }
392}
393
394impl From<u64> for RegisterValue {
395    fn from(val: u64) -> Self {
396        Self::U64(val)
397    }
398}
399
400impl From<u128> for RegisterValue {
401    fn from(val: u128) -> Self {
402        Self::U128(val)
403    }
404}
405
406impl TryInto<u32> for RegisterValue {
407    type Error = crate::Error;
408
409    fn try_into(self) -> Result<u32, Self::Error> {
410        match self {
411            Self::U32(v) => Ok(v),
412            Self::U64(v) => v
413                .try_into()
414                .map_err(|_| crate::Error::Other(format!("Value '{}' too large for u32", v))),
415            Self::U128(v) => v
416                .try_into()
417                .map_err(|_| crate::Error::Other(format!("Value '{}' too large for u32", v))),
418        }
419    }
420}
421
422impl TryInto<u64> for RegisterValue {
423    type Error = crate::Error;
424
425    fn try_into(self) -> Result<u64, Self::Error> {
426        match self {
427            Self::U32(v) => Ok(v.into()),
428            Self::U64(v) => Ok(v),
429            Self::U128(v) => v
430                .try_into()
431                .map_err(|_| crate::Error::Other(format!("Value '{}' too large for u64", v))),
432        }
433    }
434}
435
436impl TryInto<u128> for RegisterValue {
437    type Error = crate::Error;
438
439    fn try_into(self) -> Result<u128, Self::Error> {
440        match self {
441            Self::U32(v) => Ok(v.into()),
442            Self::U64(v) => Ok(v.into()),
443            Self::U128(v) => Ok(v),
444        }
445    }
446}
447
448/// Extension trait to support converting errors
449/// from TryInto calls into [Error]
450pub trait RegisterValueResultExt<T> {
451    /// Convert [Result<T,E>] into `Result<T, probe_rs::Error>`
452    fn into_crate_error(self) -> Result<T, Error>;
453}
454
455/// No translation conversion case
456impl<T> RegisterValueResultExt<T> for Result<T, Error> {
457    fn into_crate_error(self) -> Result<T, Error> {
458        self
459    }
460}
461
462/// Convert from Error = Infallible to Error = probe_rs::Error
463impl<T> RegisterValueResultExt<T> for Result<T, Infallible> {
464    fn into_crate_error(self) -> Result<T, Error> {
465        Ok(self.unwrap())
466    }
467}
468
469/// A static array of all the registers ([`CoreRegister`]) that apply to a specific architecture.
470#[derive(Debug, PartialEq)]
471pub struct CoreRegisters(Vec<&'static CoreRegister>);
472
473impl CoreRegisters {
474    /// Construct a new register file from a vector of &[`CoreRegister`]s.
475    /// The register file must contain at least the essential entries for program counter, stack pointer, frame pointer and return address registers.
476    pub fn new(core_registers: Vec<&'static CoreRegister>) -> CoreRegisters {
477        CoreRegisters(core_registers)
478    }
479
480    /// Returns an iterator over the descriptions of all the non-FPU registers of this core.
481    pub fn core_registers(&self) -> impl Iterator<Item = &CoreRegister> {
482        self.0
483            .iter()
484            .filter(|r| {
485                !r.roles.iter().any(|role| {
486                    matches!(
487                        role,
488                        RegisterRole::FloatingPoint | RegisterRole::FloatingPointStatus
489                    )
490                })
491            })
492            .cloned()
493    }
494
495    /// Returns an iterator over the descriptions of all the registers of this core.
496    pub fn all_registers(&self) -> impl Iterator<Item = &CoreRegister> {
497        self.0.iter().cloned()
498    }
499
500    /// Returns the nth platform register.
501    ///
502    /// # Panics
503    ///
504    /// Panics if the register at given index does not exist.
505    pub fn core_register(&self, index: usize) -> &CoreRegister {
506        self.core_registers().nth(index).unwrap()
507    }
508
509    /// Returns the nth platform register if it is exists, `None` otherwise.
510    pub fn get_core_register(&self, index: usize) -> Option<&CoreRegister> {
511        self.core_registers().nth(index)
512    }
513
514    /// Returns the nth argument register.
515    ///
516    /// # Panics
517    ///
518    /// Panics if the register at given index does not exist.
519    pub fn argument_register(&self, index: usize) -> &CoreRegister {
520        self.get_argument_register(index).unwrap()
521    }
522
523    /// Returns the nth argument register if it is exists, `None` otherwise.
524    pub fn get_argument_register(&self, index: usize) -> Option<&CoreRegister> {
525        self.0
526            .iter()
527            .filter(|r| {
528                r.roles
529                    .iter()
530                    .any(|role| matches!(role, RegisterRole::Argument(_)))
531            })
532            .cloned()
533            .nth(index)
534    }
535
536    /// Returns the nth result register.
537    ///
538    /// # Panics
539    ///
540    /// Panics if the register at given index does not exist.
541    pub fn result_register(&self, index: usize) -> &CoreRegister {
542        self.get_result_register(index).unwrap()
543    }
544
545    /// Returns the nth result register if it is exists, `None` otherwise.
546    pub fn get_result_register(&self, index: usize) -> Option<&CoreRegister> {
547        self.0
548            .iter()
549            .filter(|r| {
550                r.roles
551                    .iter()
552                    .any(|role| matches!(role, RegisterRole::Return(_)))
553            })
554            .cloned()
555            .nth(index)
556    }
557
558    /// The program counter.
559    pub fn pc(&self) -> Option<&CoreRegister> {
560        self.0
561            .iter()
562            .find(|r| r.register_has_role(RegisterRole::ProgramCounter))
563            .cloned()
564    }
565
566    /// The main stack pointer.
567    pub fn msp(&self) -> Option<&CoreRegister> {
568        self.0
569            .iter()
570            .find(|r| r.register_has_role(RegisterRole::MainStackPointer))
571            .cloned()
572    }
573
574    /// The process stack pointer.
575    pub fn psp(&self) -> Option<&CoreRegister> {
576        self.0
577            .iter()
578            .find(|r| r.register_has_role(RegisterRole::ProcessStackPointer))
579            .cloned()
580    }
581
582    /// The processor status register.
583    pub fn psr(&self) -> Option<&CoreRegister> {
584        self.0
585            .iter()
586            .find(|r| r.register_has_role(RegisterRole::ProcessorStatus))
587            .cloned()
588    }
589
590    /// Find any register that have a `RegisterRole::Other` and the specified name.
591    pub fn other_by_name(&self, name: &str) -> Option<&CoreRegister> {
592        self.0
593            .iter()
594            .find(|r| {
595                r.roles
596                    .iter()
597                    .any(|role| matches!(role, RegisterRole::Other(n) if *n == name))
598            })
599            .cloned()
600    }
601
602    /// The fpu status register.
603    pub fn fpsr(&self) -> Option<&CoreRegister> {
604        self.0
605            .iter()
606            .find(|r| r.register_has_role(RegisterRole::FloatingPointStatus))
607            .cloned()
608    }
609
610    /// Returns an iterator over the descriptions of all the registers of this core.
611    pub fn fpu_registers(&self) -> Option<impl Iterator<Item = &CoreRegister>> {
612        let mut fpu_registers = self
613            .0
614            .iter()
615            .filter(|r| r.register_has_role(RegisterRole::FloatingPoint))
616            .peekable();
617        if fpu_registers.peek().is_some() {
618            Some(fpu_registers.cloned())
619        } else {
620            None
621        }
622    }
623
624    /// Returns the nth fpu register.
625    ///
626    /// # Panics
627    ///
628    /// Panics if the register at given index does not exist.
629    pub fn fpu_register(&self, index: usize) -> &CoreRegister {
630        self.get_fpu_register(index).unwrap()
631    }
632
633    /// Returns the nth fpu register if it is exists, `None` otherwise.
634    pub fn get_fpu_register(&self, index: usize) -> Option<&CoreRegister> {
635        self.0
636            .iter()
637            .filter(|r| r.register_has_role(RegisterRole::FloatingPoint))
638            .cloned()
639            .nth(index)
640    }
641}