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
For some reason unknown to me if I write the code like this:
__attribute__( (naked) ) void HardFault_Handler(void) { __asm__ volatile ( "MRS R0, MSP \n" "BL System_processHardfault \n" ); } #pragma GCC optimize ("O0") void System_processHardfault(ExceptionStackContext_s *stack_content) { xPSR_Type xpsr_reg; printf("\n ---- !!! WIFI EXCEPTION !!! ---- \n\n"); 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); }
I get the correct return address, but XPSR doesn't have the correct value, and I can't figure out how to unwind the stack.I tried increasing the stack pointer (stack_content) address to see the next frame, but I don't see valid return address)
Can anyone help?