-
Notifications
You must be signed in to change notification settings - Fork 84
Backtrace for HardFault #158
Description
I was experimenting with the latest release of cortex-m-rt (0.6.6).
Possibly related to #139.
The code (below) should hard fault, and it does and the handler is invoked.
a gdb bactrace works at the first breakpoint. (I used the "asm-inline" feature, to have the bkpts inlined).
(gdb) p/x *ef
$9 = cortex_m_rt::ExceptionFrame {r0: 0x2fffffff, r1: 0xf00000, r2: 0x20000000, r3: 0x20000008, r12: 0xdfffffff, lr: 0x80006c3, pc: 0x80002f8, xpsr: 0x61000000}
seems ok. (pc being the read_volatile
on the faulty address)
However, when trying to make a backtrace from within testf
or after testf
(back in the HardFault handler), backtracing ends up in an infinite loop.
(gdb) bt
#0 HardFault (ef=<optimized out>) at examples/crash-semihosting.rs:121
#1 0x08001adc in HardFault (ef=0x2000ffe0) at examples/crash-semihosting.rs:120
#2 0x08001adc in HardFault (ef=0x2000ffe0) at examples/crash-semihosting.rs:120
I wonder if this is the expected behavior. If so, then the docs should perhaps indicate that if you want to make a backtrace, put an asm::bkptr at entry of the HardFault handler, and do the bactrace before you call any function, e.g.,
let _ = hprintln!("{:#?}", ef);
I did not use panic!(..)
to print the ef
, as I wanted the example as simple as possible (less indirections). Printing ef
can of course be done from within gdb as well, and is often preferrable as bringing formatting and semi-hosting printing is somewhat bloating the code.
On another note, I tried printing `ef' over ITM, but that is not advisable, as (at least on the stlink/nucleo 64), the internal buffer of the debug interface will overflow causing the ITM channel to be frozen). After that ITM was inaccessible, requiring an openocd kill/restart, but that behaviour might be installation dependent.
I took a brief look at the generated asm (release mode), and it looks ok, it reserves som place on the stack for the HardFault handler, etc.
...
#[entry]
#[inline(never)]
fn main() -> ! {
unsafe {
// read an address outside of the RAM region; this causes a HardFault exception
ptr::read_volatile(0x2FFF_FFFF as *const u32);
}
loop {}
}
#[inline(never)]
fn testf() {
asm::bkpt();
}
#[exception]
fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
// prints the exception frame using semihosting
asm::bkpt();
testf();
asm::bkpt();
let _ = hprintln!("{:#?}", ef);
asm::bkpt();
let _ = hprintln!("{:#?}", ef);
asm::bkpt();
loop {
asm::bkpt();
}
}