Module cortex_m_quickstart::examples::_3_crash [] [src]

Debugging a crash (exception)

The cortex-m-rt crate provides functionality for this through a default exception handler. When an exception is hit, the default handler will trigger a breakpoint and in this debugging context the stacked registers are accessible.

In you run the example below, you'll be able to inspect the state of your program under the debugger using these commands:

(gdb) # Exception frame = program state during the crash
(gdb) print/x *ef
$1 = cortex_m::exception::ExceptionFrame {
  r0 = 0x2fffffff,
  r1 = 0x2fffffff,
  r2 = 0x0,
  r3 = 0x0,
  r12 = 0x0,
  lr = 0x8000481,
  pc = 0x8000460,
  xpsr = 0x61000000,
}

(gdb) # Where did we come from?
(gdb) backtrace
#0  cortex_m_rt::default_handler (ef=0x20004f54) at (..)
#1  <signal handler called>
#2  0x08000460 in core::ptr::read_volatile<u32> (src=0x2fffffff) at (..)
#3  0x08000480 in crash::main () at examples/crash.rs:68

(gdb) # Nail down the location of the crash
(gdb) disassemble/m ef.pc
Dump of assembler code for function core::ptr::read_volatile<u32>:
408     pub unsafe fn read_volatile<T>(src: *const T) -> T {
   0x08000454 <+0>:     sub     sp, #20
   0x08000456 <+2>:     mov     r1, r0
   0x08000458 <+4>:     str     r0, [sp, #8]
   0x0800045a <+6>:     ldr     r0, [sp, #8]
   0x0800045c <+8>:     str     r0, [sp, #12]

409         intrinsics::volatile_load(src)
   0x0800045e <+10>:    ldr     r0, [sp, #12]
   0x08000460 <+12>:    ldr     r0, [r0, #0]
   0x08000462 <+14>:    str     r0, [sp, #16]
   0x08000464 <+16>:    ldr     r0, [sp, #16]
   0x08000466 <+18>:    str     r1, [sp, #4]
   0x08000468 <+20>:    str     r0, [sp, #0]
   0x0800046a <+22>:    b.n     0x800046c <core::ptr::read_volatile<u32>+24>

410     }
   0x0800046c <+24>:    ldr     r0, [sp, #0]
   0x0800046e <+26>:    add     sp, #20
   0x08000470 <+28>:    bx      lr

End of assembler dump.

#![feature(used)]
#![no_std]
 
extern crate cortex_m;
extern crate cortex_m_rt;
 
use core::ptr;
 
use cortex_m::asm;
 
fn main() {
    // Read an invalid memory address
    unsafe {
        ptr::read_volatile(0x2FFF_FFFF as *const u32);
    }
}
 
// As we are not using interrupts, we just register a dummy catch all handler
#[link_section = ".vector_table.interrupts"]
#[used]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
 
extern "C" fn default_handler() {
    asm::bkpt();
}