Skip to content

HardFaultHandling

Simon Wright edited this page Aug 19, 2018 · 3 revisions

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.

Clone this wiki locally