Stackdump Capture

crates.io Documentation

This crate defines stackdump capture functions for the platforms it is compiled for.

Also see the main repo readme.

Platform detection is done automatically in the build.rs file. This only helps with capturing the stack and the registers. If you want to capture the heap or any static data, then you'll have to do that yourself.

The crate is built on the stackdump-core crate. To get stack traces, feed the captured data into the stackdump-trace crate.

Cortex m

The cortex m capture comes in two variants: - Without FPU - Only captures and returns the core registers - With FPU - Also captures and returns the fpu registers

The fpu registers are automatically captured if the compilation target supports it. This does change the capture return type.

Example

With fpu:

```rust,ignore use stackdumpcapture::core::memoryregion::ArrayMemoryRegion; use stackdumpcore::registerdata::ArrayRegisterData;

let mut stackcapture = ArrayMemoryRegion::default(); let mut coreregisters = ArrayRegisterData::default(); let mut fpu_registers = ArrayRegisterData::default();

cortexm::interrupt::free(|cs| { stackdumpcapture::cortexm::capture(&mut stackcapture, &mut coreregisters, &mut fpuregisters, &cs) }); ```

For use when crashing (using cortex m as example target)

You probably want to do a stack dump when there's a crash so that you can send it to the server after a reboot.

To do that, you do need to do some setup yourself still. Because the stack capture can be quite big, you have to give a reference to it in the capture function. The registers are returned directly.

We need to be able to persist all the data across the reboot. If you have a filesystem or something similar, you could write it to there. But most embedded systems have got some SRAM so we could keep it in uninitialized memory.

```rust,ignore use core::mem::MaybeUninit; use stackdumpcore::memoryregion::ArrayMemoryRegion; use stackdumpcore::registerdata::ArrayRegisterData;

[link_section = ".uninit"]

static mut STACK_CAPTURE: MaybeUninit> = MaybeUninit::uninit();

[link_section = ".uninit"]

static mut COREREGISTERSCAPTURE: MaybeUninit> = MaybeUninit::uninit();

[link_section = ".uninit"]

static mut FPUREGISTERSCAPTURE: MaybeUninit> = MaybeUninit::uninit(); ```

We also need to be able to detect at bootup if a stackdump has been captured. The best way is to have an uninitialized integer present that can have a specific value to indicate the dump has been made.

```rust,ignore use core::mem::MaybeUninit;

[link_section = ".uninit"]

static mut CAPTUREINDICATOR: MaybeUninit = MaybeUninit::uninit(); const CAPTUREINDICATOR_TRUE: u32 = 0xC0DED1ED; // Code died

fn iscapturemade() -> bool { unsafe { CAPTUREINDICATOR.assumeinit() == CAPTUREINDICATORTRUE } }

fn resetcapturemade() { unsafe { CAPTURE_INDICATOR.write(0); } }

fn setcapturemade() { unsafe { CAPTUREINDICATOR.write(CAPTUREINDICATOR_TRUE); } } ```

Now we can capture a everything in e.g. a panic.

```rust,ignore

[panic_handler]

fn panic(info: &core::panic::PanicInfo) -> ! { cortexm::interrupt::free(|cs| { unsafe { stackdumpcapture::cortexm::capture( &mut *STACKCAPTURE.asmutptr(), &mut *COREREGISTERSCAPTURE.asmutptr(), &mut *FPUREGISTERSCAPTURE.asmut_ptr(), &cs ); // If you want to capture the heap or the static data, then do that here too yourself }

    set_capture_made();
});
cortex_m::peripheral::SCB::sys_reset()

} ```

In our main we can then check if there is a stackdump and send it to the server. Actually transporting the data is the responsibility of the user, but the memory regions and register data have an iter function so you can iterate over the bytes.

```rust,ignore fn main() { let server = (); // User defined

if is_capture_made() {
    reset_capture_made();

    for byte in unsafe { STACK_CAPTURE.assume_init_ref().iter() } {
        server.send(byte);
    }
    for byte in unsafe { CORE_REGISTERS_CAPTURE.assume_init_ref().iter() } {
        server.send(byte);
    }
    for byte in unsafe { FPU_REGISTERS_CAPTURE.assume_init_ref().iter() } {
        server.send(byte);
    }
}

} ```