Search code examples
debuggingarmkeil

Cortex M0 HardFault_Handler and getting the fault address


I'm having a HardFault when executing my program. I've found dozens of ways to get PC's value, but I'm using Keil uVision 5 and none of them has worked.

As far as I know I'm not in a multitasking context, and PSP contains 0xFFFFFFF1, so adding 24 to it would cause overflow.

Here's what I've managed to get working (as in, it compiles and execute):

enum { r0, r1, r2, r3, r12, lr, pc, psr};

extern "C" void HardFault_Handler()
{
  uint32_t *stack;
  __ASM volatile("MRS stack, MSP");

  stack += 0x20;

  pc = stack[pc];
  psr = stack[psr];
  __ASM volatile("BKPT #01");   
}

Note the "+= 0x20", which is here to compensate for C function stack.

Whenever I read the PC's value, it's 0. Would anyone have working code for that?

Otherwise, here's how I do it manually:

  • Put a breakpoint on HardFault_Handler (the original one)
  • When it breaks, look as MSP
  • Add 24 to its value.
  • Dump memory at that address. And there it is, 0x00000000.

What am I doing wrong?


Solution

  • A few problems with your code

    uint32_t *stack;
    __ASM volatile("MRS stack, MSP");
    

    MRS supports register destinations only. Your assembler migt be clever enough to transfer it to a temporary register first, but I'd like to see the machine code generated from that.

    If you are using some kind of multitasking system, it might use PSP instead of MSP. See the linked code below on how one can distinguish that.

    pc = stack[pc];
    psr = stack[psr];
    

    It uses the previous values of pc and psr as an index. Should be

    pc = stack[6];
    psr = stack[7];
    

    Whenever I read the PC's value, it's 0.

    Your program might actually have jumped to address 0 (e.g. through a null function pointer), tried to execute the value found there, which was probably not a valid instruction but the initial SP value from the vector table, and faulted on that. This code

    void (*f)(void) = 0;
    f();
    

    does exactly that, I'm seeing 0x00000000 at offset 24.

    Would anyone have working code for that?

    This works for me. Note the code choosing between psp and msp, and the __attribute__((naked)) directive. You could try to find some equivalent for your compiler, to prevent the compiler from allocating a stack frame at all.