Module cortex_m_quickstart::examples::_4_crash
[−]
[src]
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); }