-
Notifications
You must be signed in to change notification settings - Fork 15
HardFaultHandling
Hard Faults occur when a program misuses the processor hardware. There's a useful document from Keil, and another from FreeRTOS.
The default HardFault_Handler
supplied in this RTS merely loops indefinitely:
procedure HardFault_Handler is
begin
loop
null;
end loop;
end HardFault_Handler;
There are a few problems with decoding a hard fault in the debugger with this handler: first, it may not be obvious that your program is actually looping in the handler, so you'll have to interrupt it (C-c); second, the stack pointer may not be the one that was in use when the fault occurred; third, the processor stores a subset of the registers on the stack; and fourth, the fault registers are packed, and therefore tedious to decode.
For these reasons, an optional HardFault_Handler
is provided. Include it in your program by
with Hardfault_Handling;
pragma Unreferenced (Hardfault_Handling);
With this handler, if a hard fault occurs and you're running under the debugger, you'll see something like
Program received signal SIGTRAP, Trace/breakpoint trap.
hardfault_handling.breakpoint (state=...)
at /Users/simon/cortex-gnat-rts/common/hardfault_handling.adb:187
187 System.Machine_Code.Asm ("bkpt #0" & ASCII.LF, Volatile => True);
and now you can inspect the fault registers CFSR
(Configurable Fault Status Register), HFSR
(Hard Fault Status Register), DFSR
(Debug Fault Status Register), AFSR
(Auxiliary Fault Status Register), MMAR
(MemManage Fault Address Register), or BFAR
(Bus Fault Address Register) by name:
(gdb) p cfsr
$1 = (mmfsr => (accviol => 0, daccviol => 0, munstkerr => 0, mstkerr => 0,
mlsperr => 0, mmarvalid => 0), bfsr => (ibuserr => 0, preciserr => 0,
impreciserr => 0, unstkerr => 0, stkerr => 0, lsperr => 0,
bfarvalid => 0), usfr => (undefinstr => 0, invstate => 0, invpc => 0,
nocp => 0, unaligned => 0, divbyzero => 1))
In this case, there was a divide-by-zero error (at the end, divbyzero => 1
; this was a deliberate error with a configuration change from the default to enable the trap), and the other registers aren't actually relevant.
(gdb) p hfsr
$2 = (vecttbl => 0, forced => 1, debugevt => 0)
You can also see the registers saved by the processor:
(gdb) p state
$1 = (r0 => 10, r1 => 0, r2 => 10, r3 => 0, r12 => 2779096485,
lr => 134218511, pc => 134218622, psr => 16777216)
or
(gdb) p/x state
$2 = (r0 => 0xa, r1 => 0x0, r2 => 0xa, r3 => 0x0, r12 => 0xa5a5a5a5,
lr => 0x800030f, pc => 0x800037e, psr => 0x1000000)
On a final note, the most likely reason for a hard fault is a stack overflow.