Hard fault handler problem - Cortex-M0+

Hi all,

I use generic Cortex-M0+ with ARM Development Studio 5.

I want to create a hard fault handler that prints out call stack list (unwind the stack).

At first I try to find just the return address from the stack (the cause of the hard fault) but it doesn't seem to work. I work without RTOS so I'm supposed to be in Handler mode and always use the MSP stack. Regardless I check the bit in the control register and it, as expected, indicates the MSP stack is in use. The problem is that the MSP stack holds no return address (I force hard fault so I know the supposed return address).

I check the PSP stack as well that has some valid return address but not the correct one.

Here is my code [NMI is routed to hard fault handler as well]:

typedef struct __attribute__((packed)) ExceptionStackContext
{
    uint32_t r0;
    uint32_t r1;
    uint32_t r2;
    uint32_t r3;
    uint32_t r12;
    uint32_t lr;
    uint32_t return_address;
    uint32_t xpsr;
} ExceptionStackContext_s;

#pragma GCC optimize ("O0")
void HardFault_Handler(void) {
    enum{eMSP_STACK_USED, ePSP_STACK_USED};

    CONTROL_Type control_reg;
    xPSR_Type xpsr_reg;
    volatile ExceptionStackContext_s *stack_content;
    volatile ExceptionStackContext_s *psp_content;

    printf(""\n ---- !!! HARD FAULT EXCEPTION !!! ---- \n\n");

    control_reg = (CONTROL_Type)__get_CONTROL();

    if (control_reg.b.SPSEL == eMSP_STACK_USED)
    {
        stack_content = __get_MSP();
    }
    else
    {
        stack_content = __get_PSP();
    }
    psp_content = __get_PSP();

    xpsr_reg = (xPSR_Type)stack_content->xpsr;

    switch(xpsr_reg.b.ISR)
    {
        case eNMI_EXCEPTION:
            printf(""NMI Exception detected\n");
            break;
        case eHARDFAULT_EXCEPTION:
            printf(""Hard Fault Exception detected\n");
            break;
    }

    printf(""STACK Register r0: %x\n", stack_content->r0);
    printf(""STACK Register r1: %x\n", stack_content->r1);
    printf(""STACK Register r2: %x\n", stack_content->r2);
    printf(""STACK Register r3: %x\n", stack_content->r3);
    printf(""STACK Register r12: %x\n", stack_content->r12);
    printf(""STACK Register LR: %x\n", stack_content->lr);
    printf(""CALL STACK Return Address: %x\n", stack_content->return_address);
    printf(""STACK Register XPSR: %x\n\n", stack_content->xpsr);

}

Any ideas why I don't get the return address?

How can I unwind the stack and create a call stack list?

Thank you

Parents
  • The stack can be corrupted when a pointer is passed to a function and the function writes beyond the allowed size of the pointer. This may end up corrupting the stack. Here is one such illustration: Official Website

    include <project.h>
    /* Application level function /
    uint8 i2cRead(void);
    / HAL level function */
    void halI2cReadData(uint8 *buffer);
    int main()
    {
    volatile uint8 data = 0;
    
    for(;;)
    {
    data = i2cRead();
    CyDelay(1);
    }
    }
    #define I2C_BUFFER_SZ 64
    uint8 i2cRead(void)
    {
    uint8 i2cBuffer;
    
      halI2cReadData(&i2cBuffer);
    
      return(i2cBuffer);
    }
    void halI2cReadData(uint8 buffer)
    {
    uint8 bufIndex = 0;
    / Read I2C data from hardware /
    / Fill the buffer */
    for(bufIndex = 0; bufIndex < I2C_BUFFER_SZ; bufIndex++)
    {
    buffer[bufIndex] = bufIndex;
    }
    }
     

Reply
  • The stack can be corrupted when a pointer is passed to a function and the function writes beyond the allowed size of the pointer. This may end up corrupting the stack. Here is one such illustration: Official Website

    include <project.h>
    /* Application level function /
    uint8 i2cRead(void);
    / HAL level function */
    void halI2cReadData(uint8 *buffer);
    int main()
    {
    volatile uint8 data = 0;
    
    for(;;)
    {
    data = i2cRead();
    CyDelay(1);
    }
    }
    #define I2C_BUFFER_SZ 64
    uint8 i2cRead(void)
    {
    uint8 i2cBuffer;
    
      halI2cReadData(&i2cBuffer);
    
      return(i2cBuffer);
    }
    void halI2cReadData(uint8 buffer)
    {
    uint8 bufIndex = 0;
    / Read I2C data from hardware /
    / Fill the buffer */
    for(bufIndex = 0; bufIndex < I2C_BUFFER_SZ; bufIndex++)
    {
    buffer[bufIndex] = bufIndex;
    }
    }
     

Children