# [−] [src] Module cortex_m_quickstart::examples::_4_crash

Debugging a crash (exception)

Most crash conditions trigger a hard fault exception, whose handler is defined via `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a snapshot of the CPU registers at the moment of the exception.

This program crashes and the `HardFault` handler prints to the console the contents of the `ExceptionFrame` and then triggers a breakpoint. From that breakpoint one can see the backtrace that led to the exception.

    (gdb) continue
    Program received signal SIGTRAP, Trace/breakpoint trap.
    __bkpt () at asm/bkpt.s:3
    3         bkpt

    (gdb) backtrace
    #0  __bkpt () at asm/bkpt.s:3
    #1  0x080030b4 in cortex_m::asm::bkpt () at $$/cortex-m-0.5.0/src/asm.rs:19
    #2  rust_begin_unwind (args=..., file=..., line=99, col=5) at $$/panic-semihosting-0.2.0/src/lib.rs:87
    #3  0x08001d06 in core::panicking::panic_fmt () at libcore/panicking.rs:71
    #4  0x080004a6 in crash::hard_fault (ef=0x20004fa0) at examples/crash.rs:99
    #5  0x08000548 in UserHardFault (ef=0x20004fa0) at <exception macros>:10
    #6  0x0800093a in HardFault () at asm.s:5
    Backtrace stopped: previous frame identical to this frame (corrupt stack?)

In the console output one will find the state of the Program Counter (PC) register at the time of the exception.

    panicked at 'HardFault at ExceptionFrame {
        r0: 0x2fffffff,
        r1: 0x2fffffff,
        r2: 0x080051d4,
        r3: 0x080051d4,
        r12: 0x20000000,
        lr: 0x08000435,
        pc: 0x08000ab6,
        xpsr: 0x61000000
    }', examples/crash.rs:106:5

This register contains the address of the instruction that caused the exception. In GDB one can disassemble the program around this address to observe the instruction that caused the exception.

    (gdb) disassemble/m 0x08000ab6
    Dump of assembler code for function core::ptr::read_volatile:
    451     pub unsafe fn read_volatile<T>(src: *const T) -> T {
       0x08000aae <+0>:     sub     sp, #16
       0x08000ab0 <+2>:     mov     r1, r0
       0x08000ab2 <+4>:     str     r0, [sp, #8]

    452         intrinsics::volatile_load(src)
       0x08000ab4 <+6>:     ldr     r0, [sp, #8]
    -> 0x08000ab6 <+8>:     ldr     r0, [r0, #0]
       0x08000ab8 <+10>:    str     r0, [sp, #12]
       0x08000aba <+12>:    ldr     r0, [sp, #12]
       0x08000abc <+14>:    str     r1, [sp, #4]
       0x08000abe <+16>:    str     r0, [sp, #0]
       0x08000ac0 <+18>:    b.n     0x8000ac2 <core::ptr::read_volatile+20>

    453     }
       0x08000ac2 <+20>:    ldr     r0, [sp, #0]
       0x08000ac4 <+22>:    add     sp, #16
       0x08000ac6 <+24>:    bx      lr

    End of assembler dump.

`ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame` we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed.

    #![no_main]
    #![no_std]

    extern crate cortex_m;
    #[macro_use]
    extern crate cortex_m_rt as rt;
    extern crate panic_semihosting;

    use core::ptr;

    use rt::ExceptionFrame;

    entry!(main);

    fn main() -> ! {
        unsafe {
            // read an address outside of the RAM region; causes a HardFault exception
            ptr::read_volatile(0x2FFF_FFFF as *const u32);
        }

        loop {}
    }

    // define the hard fault handler
    exception!(HardFault, hard_fault);

    fn hard_fault(ef: &ExceptionFrame) -> ! {
        panic!("HardFault at {:#?}", ef);
    }

    // define the default exception handler
    exception!(*, default_handler);

    fn default_handler(irqn: i16) {
        panic!("Unhandled exception (IRQn = {})", irqn);
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g. `str,u8` or `String,struct:Vec,test`)