Repository: probe-rs/probe-rs
Pull request #2829 (2024-09-28 21:40:47)

Adjust PC for Xtensa and RiscV
This should fix stack traces for Risc-V ESP32 devices. It also helps with Xtensa to resolve the function name of `abort`.


Patch:
diff --git a/changelog/fixed-error-binary.md b/changelog/fixed-error-binary.md
new file mode 100644
index 00000000..d686c9f1
--- /dev/null
+++ b/changelog/fixed-error-binary.md
@@ -0,0 +1,1 @@
+Fixed an error where running a non-elf firmware results in a defmt parse error.
\ No newline at end of file
diff --git a/changelog/fixed-riscv-unwind.md b/changelog/fixed-riscv-unwind.md
new file mode 100644
index 00000000..43c456ab
--- /dev/null
+++ b/changelog/fixed-riscv-unwind.md
@@ -0,0 +1,1 @@
+Improved unwinding RISC-V stack traces
\ No newline at end of file
diff --git a/probe-rs-tools/Cargo.toml b/probe-rs-tools/Cargo.toml
index 84c368e2..73dcad10 100644
--- a/probe-rs-tools/Cargo.toml
+++ b/probe-rs-tools/Cargo.toml
@@ -46,6 +46,7 @@ directories = "5"
 dunce = "1"
 figment = { version = "0.10", features = ["toml", "json", "yaml", "env"] }
 goblin = { version = "0.8", default-features = false, features = [
+    "std",
     "elf32",
     "elf64",
     "endian_fd",
diff --git a/probe-rs-tools/src/bin/probe-rs/cmd/cargo_embed/mod.rs b/probe-rs-tools/src/bin/probe-rs/cmd/cargo_embed/mod.rs
index 686c312f..c922cb11 100644
--- a/probe-rs-tools/src/bin/probe-rs/cmd/cargo_embed/mod.rs
+++ b/probe-rs-tools/src/bin/probe-rs/cmd/cargo_embed/mod.rs
@@ -6,6 +6,7 @@ use anyhow::{anyhow, Context, Result};
 use clap::Parser;
 use colored::Colorize;
 use parking_lot::FairMutex;
+use probe_rs::flashing::FormatKind;
 use probe_rs::gdb_server::GdbInstanceConfiguration;
 use probe_rs::probe::list::Lister;
 use probe_rs::rtt::ScanRegion;
@@ -228,9 +229,14 @@ fn main_try(args: &[OsString], offset: UtcOffset) -> Result<()> {
         Err(e) => return Err(e.into()),
     };
 
-    let elf = fs::read(&path)?;
+    let format = FormatOptions::default().to_format_kind(session.target());
+    let elf = if matches!(format, FormatKind::Elf | FormatKind::Idf) {
+        Some(fs::read(&path)?)
+    } else {
+        None
+    };
     let rtt_client = RttClient::new(
-        Some(&elf),
+        elf.as_deref(),
         session.target(),
         create_rtt_config(&config).clone(),
         ScanRegion::Ram,
diff --git a/probe-rs-tools/src/bin/probe-rs/cmd/run/mod.rs b/probe-rs-tools/src/bin/probe-rs/cmd/run/mod.rs
index ec2e78d6..81e3209e 100644
--- a/probe-rs-tools/src/bin/probe-rs/cmd/run/mod.rs
+++ b/probe-rs-tools/src/bin/probe-rs/cmd/run/mod.rs
@@ -13,7 +13,7 @@ use std::time::{Duration, Instant};
 
 use anyhow::{anyhow, Result};
 use probe_rs::debug::{DebugInfo, DebugRegisters};
-use probe_rs::flashing::FileDownloadError;
+use probe_rs::flashing::{FileDownloadError, FormatKind};
 use probe_rs::{
     exception_handler_for_core,
     probe::list::Lister,
@@ -110,9 +110,21 @@ impl Cmd {
             ..Default::default()
         });
 
-        let elf = fs::read(&self.shared_options.path)?;
-        let mut rtt_client =
-            RttClient::new(Some(&elf), session.target(), rtt_config, rtt_scan_regions)?;
+        let format = self
+            .shared_options
+            .format_options
+            .to_format_kind(session.target());
+        let elf = if matches!(format, FormatKind::Elf | FormatKind::Idf) {
+            Some(fs::read(&self.shared_options.path)?)
+        } else {
+            None
+        };
+        let mut rtt_client = RttClient::new(
+            elf.as_deref(),
+            session.target(),
+            rtt_config,
+            rtt_scan_regions,
+        )?;
 
         let core_id = rtt_client.core_id();
 
diff --git a/probe-rs-tools/src/bin/probe-rs/main.rs b/probe-rs-tools/src/bin/probe-rs/main.rs
index 889b6a32..7b1609e3 100644
--- a/probe-rs-tools/src/bin/probe-rs/main.rs
+++ b/probe-rs-tools/src/bin/probe-rs/main.rs
@@ -153,13 +153,18 @@ impl FormatOptions {
     /// If a format is provided, use it.
     /// If a target has a preferred format, we use that.
     /// Finally, if neither of the above cases are true, we default to [`Format::default()`].
-    pub fn into_format(self, target: &Target) -> Format {
-        let format = self.binary_format.unwrap_or_else(|| {
+    pub fn to_format_kind(&self, target: &Target) -> FormatKind {
+        self.binary_format.unwrap_or_else(|| {
             FormatKind::from_optional(target.default_format.as_deref())
                 .expect("Failed to parse a default binary format. This shouldn't happen.")
-        });
+        })
+    }
 
-        match format {
+    /// If a format is provided, use it.
+    /// If a target has a preferred format, we use that.
+    /// Finally, if neither of the above cases are true, we default to [`Format::default()`].
+    pub fn into_format(self, target: &Target) -> Format {
+        match self.to_format_kind(target) {
             FormatKind::Bin => Format::Bin(BinOptions {
                 base_address: self.bin_options.base_address,
                 skip: self.bin_options.skip,
diff --git a/probe-rs-tools/src/bin/probe-rs/util/flash.rs b/probe-rs-tools/src/bin/probe-rs/util/flash.rs
index d4f77a03..46551c27 100644
--- a/probe-rs-tools/src/bin/probe-rs/util/flash.rs
+++ b/probe-rs-tools/src/bin/probe-rs/util/flash.rs
@@ -144,7 +144,7 @@ pub fn run_flash_download(
     logging::clear_progress_bar();
 
     logging::eprintln(format!(
-        "    {} in {}s",
+        "     {} in {:.02}s",
         "Finished".green().bold(),
         flash_timer.elapsed().as_secs_f32(),
     ));
@@ -189,20 +189,34 @@ impl ProgressBarGroup {
         }
     }
 
-    pub fn add(&mut self, bar: ProgressBar) {
-        let msg_template = "{msg:.green.bold} {spinner} [{elapsed_precise}] [{wide_bar}] {bytes:>8}/{total_bytes:>8} @ {bytes_per_sec:>10} (eta {eta:3})";
-        let style = ProgressStyle::default_bar()
+    fn idle() -> ProgressStyle {
+        ProgressStyle::with_template("{msg:.green.bold} {spinner} {percent:>3}% [{bar:20}]")
+            .expect("Error in progress bar creation. This is a bug, please report it.")
             .tick_chars("⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈✔")
             .progress_chars("--")
-            .template(msg_template)
-            .expect("Error in progress bar creation. This is a bug, please report it.");
+    }
+
+    fn active() -> ProgressStyle {
+        ProgressStyle::with_template("{msg:.green.bold} {spinner} {percent:>3}% [{bar:20}] {bytes:>10} @ {bytes_per_sec:>12} (ETA {eta})")
+            .expect("Error in progress bar creation. This is a bug, please report it.")
+            .tick_chars("⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈✔")
+            .progress_chars("##-")
+    }
 
+    fn finished() -> ProgressStyle {
+        ProgressStyle::with_template("{msg:.green.bold} {spinner} {percent:>3}% [{bar:20}] {bytes:>10} @ {bytes_per_sec:>12} (took {elapsed})")
+            .expect("Error in progress bar creation. This is a bug, please report it.")
+            .tick_chars("⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈✔")
+            .progress_chars("##")
+    }
+
+    pub fn add(&mut self, bar: ProgressBar) {
         if self.append_phase {
             bar.set_message(format!("{} {}", self.message, self.bars.len() + 1));
         } else {
             bar.set_message(self.message.clone());
         }
-        bar.set_style(style);
+        bar.set_style(Self::idle());
         bar.enable_steady_tick(Duration::from_millis(100));
         bar.reset_elapsed();
 
@@ -217,8 +231,7 @@ impl ProgressBarGroup {
 
     pub fn inc(&mut self, size: u64) {
         if let Some(bar) = self.bars.get(self.selected) {
-            let style = bar.style().progress_chars("##-");
-            bar.set_style(style);
+            bar.set_style(Self::active());
             bar.inc(size);
         }
     }
@@ -239,6 +252,7 @@ impl ProgressBarGroup {
 
     pub fn finish(&mut self) {
         if let Some(bar) = self.bars.get(self.selected) {
+            bar.set_style(Self::finished());
             bar.finish();
         }
         self.next();
diff --git a/probe-rs-tools/src/bin/probe-rs/util/rtt.rs b/probe-rs-tools/src/bin/probe-rs/util/rtt.rs
index 13825dc2..d28cbe47 100644
--- a/probe-rs-tools/src/bin/probe-rs/util/rtt.rs
+++ b/probe-rs-tools/src/bin/probe-rs/util/rtt.rs
@@ -479,6 +479,15 @@ impl fmt::Debug for DefmtState {
     }
 }
 
+/// Error type for RTT symbol lookup.
+#[derive(Debug, thiserror::Error, docsplay::Display)]
+pub enum RttSymbolError {
+    /// RTT symbol not found in the ELF file.
+    RttSymbolNotFound,
+    /// Failed to parse the firmware as an ELF file.
+    Goblin(#[source] goblin::error::Error),
+}
+
 impl RttActiveTarget {
     /// RttActiveTarget collects references to all the `RttActiveChannel`s, for latter polling/pushing of data.
     pub fn new(
@@ -523,7 +532,7 @@ impl RttActiveTarget {
     pub fn get_rtt_symbol<T: Read + Seek>(file: &mut T) -> Option<u64> {
         let mut buffer = Vec::new();
         if file.read_to_end(&mut buffer).is_ok() {
-            if let Some(rtt) = Self::get_rtt_symbol_from_bytes(buffer.as_slice()) {
+            if let Ok(rtt) = Self::get_rtt_symbol_from_bytes(buffer.as_slice()) {
                 return Some(rtt);
             }
         }
@@ -534,16 +543,18 @@ impl RttActiveTarget {
         None
     }
 
-    pub fn get_rtt_symbol_from_bytes(buffer: &[u8]) -> Option<u64> {
-        if let Ok(binary) = goblin::elf::Elf::parse(buffer) {
-            for sym in &binary.syms {
-                if binary.strtab.get_at(sym.st_name) == Some("_SEGGER_RTT") {
-                    return Some(sym.st_value);
+    pub fn get_rtt_symbol_from_bytes(buffer: &[u8]) -> Result<u64, RttSymbolError> {
+        match goblin::elf::Elf::parse(buffer) {
+            Ok(binary) => {
+                for sym in &binary.syms {
+                    if binary.strtab.get_at(sym.st_name) == Some("_SEGGER_RTT") {
+                        return Ok(sym.st_value);
+                    }
                 }
+                Err(RttSymbolError::RttSymbolNotFound)
             }
+            Err(err) => Err(RttSymbolError::Goblin(err)),
         }
-
-        None
     }
 
     /// Polls the RTT target on all channels and returns available data.
diff --git a/probe-rs-tools/src/bin/probe-rs/util/rtt/client.rs b/probe-rs-tools/src/bin/probe-rs/util/rtt/client.rs
index 7e1adaef..cf6d97ad 100644
--- a/probe-rs-tools/src/bin/probe-rs/util/rtt/client.rs
+++ b/probe-rs-tools/src/bin/probe-rs/util/rtt/client.rs
@@ -2,7 +2,7 @@ use std::sync::Arc;
 
 use crate::util::rtt::{
     ChannelDataCallbacks, DefmtState, RttActiveDownChannel, RttActiveTarget, RttActiveUpChannel,
-    RttConfig,
+    RttConfig, RttSymbolError,
 };
 use probe_rs::{
     rtt::{Error, Rtt, ScanRegion},
@@ -49,11 +49,26 @@ impl RttClient {
         };
 
         if let Some(elf) = elf {
-            if let Some(address) = RttActiveTarget::get_rtt_symbol_from_bytes(elf) {
-                this.scan_region = ScanRegion::Exact(address);
-                this.core_id = target.core_index_by_address(address).unwrap_or(0);
+            let mut init_defmt = false;
+            match RttActiveTarget::get_rtt_symbol_from_bytes(elf) {
+                Ok(address) => {
+                    this.scan_region = ScanRegion::Exact(address);
+                    this.core_id = target.core_index_by_address(address).unwrap_or(0);
+
+                    init_defmt = true;
+                }
+                Err(RttSymbolError::Goblin(_)) => {
+                    // Not an ELF
+                }
+                Err(RttSymbolError::RttSymbolNotFound) => {
+                    // We can still try to use defmt, we might find the control block.
+                    init_defmt = true;
+                }
+            }
+
+            if init_defmt {
+                this.defmt_data = DefmtState::try_from_bytes(elf)?.map(Arc::new);
             }
-            this.defmt_data = DefmtState::try_from_bytes(elf)?.map(Arc::new);
         }
 
         Ok(this)
diff --git a/probe-rs/src/debug/debug_info.rs b/probe-rs/src/debug/debug_info.rs
index f2c6ae4c..bf5cf891 100644
--- a/probe-rs/src/debug/debug_info.rs
+++ b/probe-rs/src/debug/debug_info.rs
@@ -1156,12 +1156,22 @@ pub fn unwind_register(
                     .core_register
                     .register_has_role(RegisterRole::ProgramCounter) =>
                 {
+                    let Ok(current_pc) = callee_frame_registers
+                        .get_register_value_by_role(&RegisterRole::ProgramCounter)
+                    else {
+                        return ControlFlow::Break(
+                            crate::Error::Other(
+                                "UNWIND: Tried to unwind return address value where current program counter is unknown.".to_string()
+                            )
+                        );
+                    };
                     // NOTE: PC = Value of the unwound LR, i.e. the first instruction after the one that called this function.
                     // If both the LR and PC registers have undefined rules, this will prevent the unwind from continuing.
                     register_rule_string = "PC=(unwound LR) (dwarf Undefined)".to_string();
                     unwound_return_address.and_then(|return_address| {
                         unwind_program_counter_register(
                             return_address,
+                            current_pc,
                             instruction_set,
                             &mut register_rule_string,
                         )
@@ -1281,6 +1291,7 @@ pub fn unwind_register(
 /// Helper function to determine the program counter value for the previous frame.
 fn unwind_program_counter_register(
     return_address: RegisterValue,
+    current_pc: u64,
     instruction_set: Option<InstructionSet>,
     register_rule_string: &mut String,
 ) -> Option<RegisterValue> {
@@ -1291,15 +1302,32 @@ fn unwind_program_counter_register(
 
     match return_address {
         RegisterValue::U32(return_address) => {
-            if instruction_set == Some(InstructionSet::Thumb2) {
-                // NOTE: [ARMv7-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0403/ee), Section A5.1.2:
-                //
-                // We have to clear the last bit to ensure the PC is half-word aligned. (on ARM architecture,
-                // when in Thumb state for certain instruction types will set the LSB to 1)
-                *register_rule_string = "PC=(unwound LR & !0b1) (dwarf Undefined)".to_string();
-                Some(RegisterValue::U32(return_address & !0b1))
-            } else {
-                Some(RegisterValue::U32(return_address))
+            match instruction_set {
+                Some(InstructionSet::Thumb2) => {
+                    // NOTE: [ARMv7-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0403/ee), Section A5.1.2:
+                    //
+                    // We have to clear the last bit to ensure the PC is half-word aligned. (on ARM architecture,
+                    // when in Thumb state for certain instruction types will set the LSB to 1)
+                    *register_rule_string = "PC=(unwound LR & !0b1) (dwarf Undefined)".to_string();
+                    Some(RegisterValue::U32(return_address & !0b1))
+                }
+                Some(InstructionSet::RV32C) => {
+                    *register_rule_string = "PC=(unwound x1 - 2) (dwarf Undefined)".to_string();
+                    Some(RegisterValue::U32(return_address - 2))
+                }
+                Some(InstructionSet::RV32) => {
+                    *register_rule_string = "PC=(unwound x1 - 4) (dwarf Undefined)".to_string();
+                    Some(RegisterValue::U32(return_address - 4))
+                }
+                Some(InstructionSet::Xtensa) => {
+                    // TODO: detect CALL0
+                    let upper_bits = (current_pc as u32) & 0xC000_0000;
+                    *register_rule_string = "PC=(unwound x0 - 3) (dwarf Undefined)".to_string();
+                    Some(RegisterValue::U32(
+                        (return_address & 0x3FFF_FFFF | upper_bits) - 3,
+                    ))
+                }
+                _ => Some(RegisterValue::U32(return_address)),
             }
         }
         RegisterValue::U64(return_address) => Some(RegisterValue::U64(return_address)),
diff --git a/probe-rs/src/debug/exception_handling.rs b/probe-rs/src/debug/exception_handling.rs
index 00e76b59..f6b21ef2 100644
--- a/probe-rs/src/debug/exception_handling.rs
+++ b/probe-rs/src/debug/exception_handling.rs
@@ -58,9 +58,7 @@ impl ExceptionInterface for UnimplementedExceptionHandler {
         &self,
         _stackframe_registers: &crate::debug::DebugRegisters,
     ) -> Result<u32, DebugError> {
-        Err(DebugError::NotImplemented(
-            "Not implemented for this architecture.",
-        ))
+        Err(DebugError::NotImplemented("raw exception"))
     }
 
     fn exception_description(
diff --git a/probe-rs/src/flashing/download.rs b/probe-rs/src/flashing/download.rs
index 96948b22..4d12f68d 100644
--- a/probe-rs/src/flashing/download.rs
+++ b/probe-rs/src/flashing/download.rs
@@ -33,7 +33,7 @@ pub struct IdfOptions {
 }
 
 /// A finite list of all the available binary formats probe-rs understands.
-#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
 pub enum FormatKind {
     /// Marks a file in binary format. This means that the file contains the contents of the flash 1:1.
     /// [BinOptions] can be used to define the location in flash where the file contents should be put at.


Test patch:
diff --git a/probe-rs/src/debug/snapshots/probe_rs__debug__debug_info__test__esp32c3_full_unwind.snap b/probe-rs/src/debug/snapshots/probe_rs__debug__debug_info__test__esp32c3_full_unwind.snap
index bec6b046..1fc0eb25 100644
--- a/probe-rs/src/debug/snapshots/probe_rs__debug__debug_info__test__esp32c3_full_unwind.snap
+++ b/probe-rs/src/debug/snapshots/probe_rs__debug__debug_info__test__esp32c3_full_unwind.snap
@@ -675,9 +675,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107350508
+        U32: 1107350506
   pc:
-    U32: 1107350508
+    U32: 1107350506
   frame_base: 1070395504
   is_inlined: false
   local_variables:
@@ -1008,9 +1008,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107350508
+        U32: 1107350506
   pc:
-    U32: 1107350508
+    U32: 1107350506
   frame_base: 1070395648
   is_inlined: false
   local_variables:
@@ -1341,9 +1341,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107350508
+        U32: 1107350506
   pc:
-    U32: 1107350508
+    U32: 1107350506
   frame_base: 1070395792
   is_inlined: false
   local_variables:
@@ -1674,9 +1674,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107350508
+        U32: 1107350506
   pc:
-    U32: 1107350508
+    U32: 1107350506
   frame_base: 1070395936
   is_inlined: false
   local_variables:
@@ -2007,9 +2007,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107350508
+        U32: 1107350506
   pc:
-    U32: 1107350508
+    U32: 1107350506
   frame_base: 1070396080
   is_inlined: false
   local_variables:
@@ -2340,9 +2340,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107350304
+        U32: 1107350302
   pc:
-    U32: 1107350304
+    U32: 1107350302
   frame_base: 1070396224
   is_inlined: false
   local_variables:
@@ -4984,7 +4984,7 @@ expression: stack_frames
   source_location:
     line: 26
     column:
-      Column: 10
+      Column: 54
     file: esp32c3.rs
     directory: /Users/jacknoppe/dev/debug/probe-rs-debugger-test/src/bin
   registers:
@@ -5296,9 +5296,9 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107297628
+        U32: 1107297626
   pc:
-    U32: 1107297628
+    U32: 1107297626
   frame_base: 1070399200
   is_inlined: false
   local_variables:
@@ -5898,12 +5898,13 @@ expression: stack_frames
                     Base: u64
                   value: "16000000"
   canonical_frame_address: 1070399392
-- function_name: fmt
+- function_name: hal_main
   source_location:
-    line: 31
-    column: LeftEdge
-    file: riscv.rs
-    directory: /Users/jacknoppe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-hal-0.17.0/src/interrupt
+    line: 521
+    column:
+      Column: 9
+    file: lib.rs
+    directory: /Users/jacknoppe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-hal-0.17.0/src
   registers:
     - core_register:
         id: 4096
@@ -6208,122 +6209,379 @@ expression: stack_frames
           UnsignedInteger: 32
       dwarf_id: ~
       value:
-        U32: 1107304768
+        U32: 1107304766
   pc:
-    U32: 1107304768
+    U32: 1107304766
   frame_base: 1070399392
   is_inlined: false
   local_variables:
     Child Variables:
       name: LocalScopeRoot
       type_name: Unknown
-      value: "<unknown> {\n\tself: &esp_hal::interrupt::riscv::Error = &esp_hal::interrupt::riscv::Error @ 0x3FCCFFB4,\n\tf: &mut core::fmt::Formatter = &mut core::fmt::Formatter @ 0x3FCCFFB8}"
+      value: "<unknown> {\n\ta0: usize = 0,\n\ta1: usize = 0,\n\ta2: usize = 0,\n\tstack_chk_guard: *mut u32 = *mut u32 @ 0x3FCCFFC0}"
       children:
         - name:
-            Named: self
+            Named: a0
           type_name:
-            Pointer: "&esp_hal::interrupt::riscv::Error"
-          value: "&esp_hal::interrupt::riscv::Error @ 0x3FCCFFB4"
-          children:
-            - name:
-                Named: "*self"
-              type_name:
-                Enum: Error
-              value: "Error::InvalidInterruptPriority"
+            Base: usize
+          value: "0"
+        - name:
+            Named: a1
+          type_name:
+            Base: usize
+          value: "0"
+        - name:
+            Named: a2
+          type_name:
+            Base: usize
+          value: "0"
         - name:
-            Named: f
+            Named: stack_chk_guard
           type_name:
-            Pointer: "&mut core::fmt::Formatter"
-          value: "&mut core::fmt::Formatter @ 0x3FCCFFB8"
+            Pointer: "*mut u32"
+          value: "*mut u32 @ 0x3FCCFFC0"
           children:
             - name:
-                Named: "*f"
+                Named: "*stack_chk_guard"
               type_name:
-                Struct: Formatter
-              value: Formatter @ 0x00000000
-              children:
-                - name:
-                    Named: flags
-                  type_name:
-                    Base: u32
-                  value: "0"
-                - name:
-                    Named: fill
-                  type_name:
-                    Base: char
-                  value: "\u0000"
-                - name:
-                    Named: align
-                  type_name:
-                    Enum: Alignment
-                  value: "Alignment::Left"
-                - name:
-                    Named: width
-                  type_name:
-                    Struct: Option<usize>
-                  value: Option<usize> @ 0x00000000
-                  children:
-                    - name:
-                        Named: None
-                      type_name:
-                        Struct: None
-                      value: None @ 0x00000000
-                - name:
-                    Named: precision
-                  type_name:
-                    Struct: Option<usize>
-                  value: Option<usize> @ 0x00000008
-                  children:
-                    - name:
-                        Named: None
-                      type_name:
-                        Struct: None
-                      value: None @ 0x00000008
-                - name:
-                    Named: buf
-                  type_name:
-                    Struct: "&mut dyn core::fmt::Write"
-                  value: "&mut dyn core::fmt::Write @ 0x00000014"
-                  children:
-                    - name:
-                        Named: pointer
-                      type_name:
-                        Pointer: "dyn core::fmt::Write"
-                      value: "*raw dyn core::fmt::Write @ 0x00000014"
-                      children:
-                        - name:
-                            Named: "*pointer"
-                          type_name:
-                            Struct: "dyn core::fmt::Write"
-                          value: "dyn core::fmt::Write @ 0x00000000"
-                    - name:
-                        Named: vtable
-                      type_name:
-                        Pointer: "&[usize; 3]"
-                      value: "&[usize; 3] @ 0x00000018"
-                      children:
-                        - name:
-                            Named: "*vtable"
-                          type_name:
-                            Array:
-                              item_type_name:
-                                Base: usize
-                              count: 3
-                          value: "[usize; 3] = [\n\t0,\n\t0,\n\t0]"
-                          children:
-                            - name:
-                                Named: __0
-                              type_name:
-                                Base: usize
-                              value: "0"
-                            - name:
-                                Named: __1
-                              type_name:
-                                Base: usize
-                              value: "0"
-                            - name:
-                                Named: __2
-                              type_name:
-                                Base: usize
-                              value: "0"
-  canonical_frame_address: 1070399392
+                Base: u32
+              value: "< Probe(Other(\"The coredump does not include the memory for address 0x3fc825f4 of size 0x4\")) >"
+  canonical_frame_address: 1070399440
+- function_name: start_rust
+  source_location:
+    line: 70
+    column:
+      Column: 5
+    file: lib.rs
+    directory: /Users/jacknoppe/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-riscv-rt-0.8.0/src
+  registers:
+    - core_register:
+        id: 4096
+        roles:
+          - Core: x0
+          - Other: zero
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 0
+      value: ~
+    - core_register:
+        id: 4097
+        roles:
+          - Core: x1
+          - ReturnAddress
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 1
+      value:
+        U32: 1107296516
+    - core_register:
+        id: 4098
+        roles:
+          - Core: x2
+          - StackPointer
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 2
+      value:
+        U32: 1070399440
+    - core_register:
+        id: 4099
+        roles:
+          - Core: x3
+          - Other: gp
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 3
+      value: ~
+    - core_register:
+        id: 4100
+        roles:
+          - Core: x4
+          - Other: tp
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 4
+      value: ~
+    - core_register:
+        id: 4101
+        roles:
+          - Core: x5
+          - Other: t0
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 5
+      value: ~
+    - core_register:
+        id: 4102
+        roles:
+          - Core: x6
+          - Other: t1
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 6
+      value: ~
+    - core_register:
+        id: 4103
+        roles:
+          - Core: x7
+          - Other: t2
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 7
+      value: ~
+    - core_register:
+        id: 4104
+        roles:
+          - Core: x8
+          - FramePointer
+          - Other: s0
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 8
+      value:
+        U32: 1070399440
+    - core_register:
+        id: 4105
+        roles:
+          - Core: x9
+          - Other: s1
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 9
+      value: ~
+    - core_register:
+        id: 4106
+        roles:
+          - Core: x10
+          - Argument: a0
+          - Return: r0
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 10
+      value: ~
+    - core_register:
+        id: 4107
+        roles:
+          - Core: x11
+          - Argument: a1
+          - Return: r1
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 11
+      value: ~
+    - core_register:
+        id: 4108
+        roles:
+          - Core: x12
+          - Argument: a2
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 12
+      value: ~
+    - core_register:
+        id: 4109
+        roles:
+          - Core: x13
+          - Argument: a3
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 13
+      value: ~
+    - core_register:
+        id: 4110
+        roles:
+          - Core: x14
+          - Argument: a4
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 14
+      value: ~
+    - core_register:
+        id: 4111
+        roles:
+          - Core: x15
+          - Argument: a5
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 15
+      value: ~
+    - core_register:
+        id: 4112
+        roles:
+          - Core: x16
+          - Argument: a6
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 16
+      value: ~
+    - core_register:
+        id: 4113
+        roles:
+          - Core: x17
+          - Argument: a7
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 17
+      value: ~
+    - core_register:
+        id: 4114
+        roles:
+          - Core: x18
+          - Other: s2
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 18
+      value: ~
+    - core_register:
+        id: 4115
+        roles:
+          - Core: x19
+          - Other: s3
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 19
+      value: ~
+    - core_register:
+        id: 4116
+        roles:
+          - Core: x20
+          - Other: s4
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 20
+      value: ~
+    - core_register:
+        id: 4117
+        roles:
+          - Core: x21
+          - Other: s5
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 21
+      value: ~
+    - core_register:
+        id: 4118
+        roles:
+          - Core: x22
+          - Other: s6
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 22
+      value: ~
+    - core_register:
+        id: 4119
+        roles:
+          - Core: x23
+          - Other: s7
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 23
+      value: ~
+    - core_register:
+        id: 4120
+        roles:
+          - Core: x24
+          - Other: s8
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 24
+      value: ~
+    - core_register:
+        id: 4121
+        roles:
+          - Core: x25
+          - Other: s9
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 25
+      value: ~
+    - core_register:
+        id: 4122
+        roles:
+          - Core: x26
+          - Other: s10
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 26
+      value: ~
+    - core_register:
+        id: 4123
+        roles:
+          - Core: x27
+          - Other: s11
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 27
+      value: ~
+    - core_register:
+        id: 4124
+        roles:
+          - Core: x28
+          - Other: t3
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 28
+      value: ~
+    - core_register:
+        id: 4125
+        roles:
+          - Core: x29
+          - Other: t4
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 29
+      value: ~
+    - core_register:
+        id: 4126
+        roles:
+          - Core: x30
+          - Other: t5
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 30
+      value: ~
+    - core_register:
+        id: 4127
+        roles:
+          - Core: x31
+          - Other: t6
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: 31
+      value: ~
+    - core_register:
+        id: 1969
+        roles:
+          - Core: pc
+          - ProgramCounter
+        data_type:
+          UnsignedInteger: 32
+      dwarf_id: ~
+      value:
+        U32: 1107296514
+  pc:
+    U32: 1107296514
+  frame_base: 1070399440
+  is_inlined: false
+  local_variables:
+    Child Variables:
+      name: LocalScopeRoot
+      type_name: Unknown
+      value: "<unknown> {\n\ta0: usize = 0,\n\ta1: usize = 0,\n\ta2: usize = 0}"
+      children:
+        - name:
+            Named: a0
+          type_name:
+            Base: usize
+          value: "0"
+        - name:
+            Named: a1
+          type_name:
+            Base: usize
+          value: "0"
+        - name:
+            Named: a2
+          type_name:
+            Base: usize
+          value: "0"
+  canonical_frame_address: 1070399472