Repository: probe-rs/probe-rs
Pull request #3371 (2025-05-23 16:22:21)

Add `DebugRegisters::from_coredump`


Patch:
diff --git a/changelog/added-debug-registers-from-coredump.md b/changelog/added-debug-registers-from-coredump.md
new file mode 100644
index 00000000..2359373b
--- /dev/null
+++ b/changelog/added-debug-registers-from-coredump.md
@@ -0,0 +1,1 @@
+Added `DebugRegisters::from_coredump`
\ No newline at end of file
diff --git a/probe-rs-debug/src/debug_info.rs b/probe-rs-debug/src/debug_info.rs
index 1b0aa650..1706a0dd 100644
--- a/probe-rs-debug/src/debug_info.rs
+++ b/probe-rs-debug/src/debug_info.rs
@@ -1426,7 +1426,6 @@ mod test {
             exception_handler_for_core,
         },
         stack_frame::{StackFrameInfo, TestFormatter},
-        test::debug_registers,
     };
 
     use gimli::RegisterRule;
@@ -1940,7 +1939,7 @@ mod test {
         let mut adapter = CoreDump::load_raw(coredump).unwrap();
         let debug_info = DebugInfo::from_file(elf).unwrap();
 
-        let initial_registers = debug_registers(&adapter);
+        let initial_registers = DebugRegisters::from_coredump(&adapter);
         let exception_handler = exception_handler_for_core(adapter.core_type());
         let instruction_set = adapter.instruction_set();
 
@@ -1985,7 +1984,7 @@ mod test {
 
         let snapshot_name = test_name.to_string();
 
-        let initial_registers = debug_registers(&adapter);
+        let initial_registers = DebugRegisters::from_coredump(&adapter);
         let exception_handler = exception_handler_for_core(adapter.core_type());
         let instruction_set = adapter.instruction_set();
 
@@ -2037,7 +2036,7 @@ mod test {
         let coredump_path = coredump_path(format!("debug-unwind-tests/{chip_name}"));
         let mut adapter = CoreDump::load(&coredump_path).unwrap();
 
-        let initial_registers = debug_registers(&adapter);
+        let initial_registers = DebugRegisters::from_coredump(&adapter);
 
         let snapshot_name = format!("{chip_name}_static_variables");
 
diff --git a/probe-rs-debug/src/lib.rs b/probe-rs-debug/src/lib.rs
index 8e398dd8..6df54520 100644
--- a/probe-rs-debug/src/lib.rs
+++ b/probe-rs-debug/src/lib.rs
@@ -26,9 +26,6 @@ pub mod variable_cache;
 
 pub(crate) mod exception_handling;
 
-#[cfg(test)]
-mod test;
-
 pub use self::{
     debug_info::*, debug_step::SteppingMode, exception_handling::exception_handler_for_core,
     registers::*, source_instructions::SourceLocation, source_instructions::VerifiedBreakpoint,
diff --git a/probe-rs-debug/src/registers.rs b/probe-rs-debug/src/registers.rs
index 5faaf7df..cf76c345 100644
--- a/probe-rs-debug/src/registers.rs
+++ b/probe-rs-debug/src/registers.rs
@@ -1,7 +1,8 @@
 use std::ops::Range;
 
 use probe_rs::{
-    CoreInterface, CoreRegister, Error, RegisterDataType, RegisterId, RegisterRole, RegisterValue,
+    CoreDump, CoreInterface, CoreRegister, CoreRegisters, Error, RegisterDataType, RegisterId,
+    RegisterRole, RegisterValue,
 };
 use serde::Serialize;
 
@@ -81,11 +82,37 @@ impl DebugRegister {
 pub struct DebugRegisters(pub Vec<DebugRegister>);
 
 impl DebugRegisters {
-    /// Read all registers defined in [`crate::core::CoreRegisters`] from the given core.
+    /// Read all registers defined in [`probe_rs::core::CoreRegisters`] from the given core.
     pub fn from_core(core: &mut impl CoreInterface) -> Self {
-        let mut debug_registers = Vec::<DebugRegister>::new();
+        Self::from_core_registers(core.registers(), |register_id| {
+            core.read_core_reg(*register_id)
+                .inspect_err(|error| {
+                    tracing::warn!(
+                        "Failed to read value for register {:?}: {error}",
+                        register_id
+                    )
+                })
+                .ok()
+        })
+    }
 
-        for (dwarf_id, core_register) in core.registers().core_registers().enumerate() {
+    /// Read all registers captured in the given [`CoreDump`].
+    pub fn from_coredump(core: &CoreDump) -> Self {
+        Self::from_core_registers(core.registers(), |register_id| {
+            let value = core.registers.get(register_id).cloned();
+            if value.is_none() {
+                tracing::warn!("Failed to read value for register {:?}", register_id);
+            }
+            value
+        })
+    }
+
+    fn from_core_registers(
+        regs: &'static CoreRegisters,
+        mut reg_value: impl FnMut(&RegisterId) -> Option<RegisterValue>,
+    ) -> Self {
+        let mut debug_registers = Vec::<DebugRegister>::new();
+        for (dwarf_id, core_register) in regs.core_registers().enumerate() {
             // Check to ensure the register type is compatible with u64.
             if matches!(core_register.data_type(), RegisterDataType::UnsignedInteger(size_in_bits) if size_in_bits <= 64)
             {
@@ -97,17 +124,7 @@ impl DebugRegisters {
                     } else {
                         None
                     },
-                    value: match core.read_core_reg(core_register.id()) {
-                        Ok::<RegisterValue, _>(register_value) => Some(register_value),
-                        Err(e) => {
-                            tracing::warn!(
-                                "Failed to read value for register {:?}: {}",
-                                core_register,
-                                e
-                            );
-                            None
-                        }
-                    },
+                    value: reg_value(&core_register.id()),
                 });
             } else {
                 tracing::trace!(
diff --git a/probe-rs/src/core/dump.rs b/probe-rs/src/core/dump.rs
index fa700be5..4da22889 100644
--- a/probe-rs/src/core/dump.rs
+++ b/probe-rs/src/core/dump.rs
@@ -1,7 +1,14 @@
+use crate::architecture::arm::core::registers::aarch32::{
+    AARCH32_CORE_REGISTERS, AARCH32_WITH_FP_16_CORE_REGISTERS, AARCH32_WITH_FP_32_CORE_REGISTERS,
+};
+use crate::architecture::arm::core::registers::aarch64::AARCH64_CORE_REGISTERS;
+use crate::architecture::arm::core::registers::cortex_m::{
+    CORTEX_M_CORE_REGISTERS, CORTEX_M_WITH_FP_CORE_REGISTERS,
+};
 use crate::architecture::riscv::registers::RISCV_CORE_REGISTERS;
 use crate::architecture::xtensa::arch::{Register as XtensaRegister, SpecialRegister};
 use crate::architecture::xtensa::registers::XTENSA_CORE_REGISTERS;
-use crate::{Core, CoreType, Error, InstructionSet, MemoryInterface};
+use crate::{Core, CoreRegisters, CoreType, Error, InstructionSet, MemoryInterface};
 use crate::{RegisterId, RegisterValue};
 use object::elf::PT_NOTE;
 use object::read::elf::ProgramHeader;
@@ -341,6 +348,44 @@ impl CoreDump {
         }
         Ok(())
     }
+
+    /// Returns the register map for the core type.
+    pub fn registers(&self) -> &'static CoreRegisters {
+        match self.core_type {
+            CoreType::Armv6m => &CORTEX_M_CORE_REGISTERS,
+            CoreType::Armv7a => match self.floating_point_register_count {
+                Some(16) => &AARCH32_WITH_FP_16_CORE_REGISTERS,
+                Some(32) => &AARCH32_WITH_FP_32_CORE_REGISTERS,
+                _ => &AARCH32_CORE_REGISTERS,
+            },
+            CoreType::Armv7m => {
+                if self.fpu_support {
+                    &CORTEX_M_WITH_FP_CORE_REGISTERS
+                } else {
+                    &CORTEX_M_CORE_REGISTERS
+                }
+            }
+            CoreType::Armv7em => {
+                if self.fpu_support {
+                    &CORTEX_M_WITH_FP_CORE_REGISTERS
+                } else {
+                    &CORTEX_M_CORE_REGISTERS
+                }
+            }
+            // TODO: This can be wrong if the CPU is 32 bit. For lack of better design at the time
+            // of writing this code this differentiation has been omitted.
+            CoreType::Armv8a => &AARCH64_CORE_REGISTERS,
+            CoreType::Armv8m => {
+                if self.fpu_support {
+                    &CORTEX_M_WITH_FP_CORE_REGISTERS
+                } else {
+                    &CORTEX_M_CORE_REGISTERS
+                }
+            }
+            CoreType::Riscv => &RISCV_CORE_REGISTERS,
+            CoreType::Xtensa => &XTENSA_CORE_REGISTERS,
+        }
+    }
 }
 
 impl MemoryInterface for CoreDump {


Test patch:
diff --git a/probe-rs-debug/src/test.rs b/probe-rs-debug/src/test.rs
deleted file mode 100644
index ddaa8a6f..00000000
--- a/probe-rs-debug/src/test.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-//! Helper functions for testing
-
-use probe_rs::{
-    CoreDump, CoreType, RegisterDataType,
-    architecture::{
-        arm::core::registers::{
-            aarch32::{
-                AARCH32_CORE_REGISTERS, AARCH32_WITH_FP_16_CORE_REGISTERS,
-                AARCH32_WITH_FP_32_CORE_REGISTERS,
-            },
-            aarch64::AARCH64_CORE_REGISTERS,
-            cortex_m::{CORTEX_M_CORE_REGISTERS, CORTEX_M_WITH_FP_CORE_REGISTERS},
-        },
-        riscv::registers::RISCV_CORE_REGISTERS,
-        xtensa::registers::XTENSA_CORE_REGISTERS,
-    },
-};
-
-use crate::{DebugRegister, DebugRegisters};
-
-/// Read all registers defined in [`crate::core::CoreRegisters`] from the given core.
-///
-/// This is currently only used for testing.
-pub(crate) fn debug_registers(core: &CoreDump) -> DebugRegisters {
-    let reg_list = match core.core_type {
-        CoreType::Armv6m => &CORTEX_M_CORE_REGISTERS,
-        CoreType::Armv7a => match core.floating_point_register_count {
-            Some(16) => &AARCH32_WITH_FP_16_CORE_REGISTERS,
-            Some(32) => &AARCH32_WITH_FP_32_CORE_REGISTERS,
-            _ => &AARCH32_CORE_REGISTERS,
-        },
-        CoreType::Armv7m => {
-            if core.fpu_support {
-                &CORTEX_M_WITH_FP_CORE_REGISTERS
-            } else {
-                &CORTEX_M_CORE_REGISTERS
-            }
-        }
-        CoreType::Armv7em => {
-            if core.fpu_support {
-                &CORTEX_M_WITH_FP_CORE_REGISTERS
-            } else {
-                &CORTEX_M_CORE_REGISTERS
-            }
-        }
-        // TODO: This can be wrong if the CPU is 32 bit. For lack of better design at the time
-        // of writing this code this differentiation has been omitted.
-        CoreType::Armv8a => &AARCH64_CORE_REGISTERS,
-        CoreType::Armv8m => {
-            if core.fpu_support {
-                &CORTEX_M_WITH_FP_CORE_REGISTERS
-            } else {
-                &CORTEX_M_CORE_REGISTERS
-            }
-        }
-        CoreType::Riscv => &RISCV_CORE_REGISTERS,
-        CoreType::Xtensa => &XTENSA_CORE_REGISTERS,
-    };
-
-    let mut debug_registers = Vec::<DebugRegister>::new();
-    for (dwarf_id, core_register) in reg_list.core_registers().enumerate() {
-        // Check to ensure the register type is compatible with u64.
-        if matches!(core_register.data_type(), RegisterDataType::UnsignedInteger(size_in_bits) if size_in_bits <= 64)
-        {
-            debug_registers.push(DebugRegister {
-                core_register,
-                // The DWARF register ID is only valid for the first 32 registers.
-                dwarf_id: if dwarf_id < 32 {
-                    Some(dwarf_id as u16)
-                } else {
-                    None
-                },
-                value: match core.registers.get(&core_register.id()) {
-                    Some(register_value) => Some(*register_value),
-                    None => {
-                        tracing::warn!("Failed to read value for register {:?}", core_register);
-                        None
-                    }
-                },
-            });
-        } else {
-            tracing::trace!(
-                "Unwind will use the default rule for this register : {:?}",
-                core_register
-            );
-        }
-    }
-    DebugRegisters(debug_registers)
-}