2020-10-06 05:14 AM
Hello
I have STM32F407VG MCU with STM32CubeIDE
I want to unwind the stack
I've found answers online and I've tried that code
The code works fine after a hardfault happens
I tried to use the same code within running (no fault happens) but couldn't do that
The stack has the exact same value
I unwind the stack inside an IRQ and I want to know where the code was before the IRQ got called
Here's the IRQ code:
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
if(++iwdg_timer >= Get_IWDG_Threshold()){
uint32_t lrStacked[5] = {0};
uint32_t topFp = __get_LR();
uint32_t nextFp = (uint32_t)&topFp;
Stack_Unwind(256, nextFp, lrStacked, 5);
//RTC_Write_LR_Stack(lrStacked);
}
/*
if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKUP_WDG_MAX) < iwdg_timer){
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKUP_WDG_MAX, iwdg_timer);
}
*/
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4);
/* USER CODE BEGIN TIM4_IRQn 1 */
/* USER CODE END TIM4_IRQn 1 */
}
static void Stack_Unwind(uint32_t iteration, uint32_t nextFp, uint32_t *lrStacked, uint32_t size){
/* loop backtrace using lr to unwind the call stack */
for(uint32_t i=0, j=0; i<iteration; i++){
uint32_t lr = *((uint32_t*)nextFp);
if((lr >= 0x08000000) && (lr <= 0x080FFFFF)){
lrStacked[j] = lr;
j++;
}
nextFp = nextFp + 4;
if (nextFp == 0x20020000 || j == size){
break;
}
}
}
__STATIC_FORCEINLINE uint32_t __get_LR(void)
{
uint32_t result;
__ASM volatile ("MOV %0, lr\n" : "=r" (result) );
return(result);
}
2020-10-06 10:40 AM
line 31 nextFp = nextFp + 4; look suspicious. Needs a pointer dereferencing.
2020-10-06 11:17 PM
Wouldn't the dereferencing in line 26 be enough?
For now, I've replaced line 6 with this:
uint32_t topFp = __get_PSP(); //or __get_MSP();
It seems that it's working but I don't think this is the right way to do it
2020-10-06 11:26 PM
I've changed line 31 to this:
nextFp = *((uint32_t*)nextFp + 4);
But now I'm getting 0 except for the first iteration
2020-10-07 12:14 AM
In C and C++, when you add an integer to a pointer, you are offsetting the pointer by that many of the things being pointed-to.
So in the line nextFp = *((uint32_t*)nextFp + 4); you are adding 4 lots of uint32_t to the pointer - in other words by 16 bytes.
Are you sure that's what you want?
2020-10-07 12:22 AM
I've tried this and and it's giving me hardfault exception
nextFp = *((uint32_t*)nextFp + 1);
Anyway, in this particular case, I don't think dereferencing is right
With the original line: nextFp = nextFp + 4;, I'm moving in the RAM to the end of it. i.e. 0x20020000
And the dereference happens in line 26
Kindly, correct me if I'm wrong
2020-10-07 01:13 AM
The lines
nextFp = nextFp + 4;
and
nextFp = *((uint32_t*)nextFp + 1);
do very different things.
The first one adds 4 to nextFp
The second sets nextFp to the contents of the memory-location pointed-to by nextFp offset by 4 bytes.
If it were me, I would set a breakpoint inside your IRQ and single-step from there.
One thought: What happens with routines that do not create stack frames? (I remember a compiler option to ensure that every routine creates a stack frame, and you have not mentioned if you selected that option).
2020-10-07 01:32 AM
Yeah. In general automated stack unwinding in thumb2 mode without using debug info seems impossible, even when r7 as frame pointer is enforced (-fno-omit-frame-pointer):
Here is an interesting approach using debug info: https://github.com/red-rocket-computing/backtrace
2020-10-07 01:40 AM
Thank you for your reply
Yes, I'm aware they're different
I just tried the dereferencing since @KnarfB suggested to
I tried it and it was wrong
So I returned to the original line mentioned in the given code snippet
I did set up a breakpoint inside the IRQ and traced the code
It seems logically fine
nextFp starts at < 0x20020000 and keeps incrementing by 4 till it reaches 0x20020000 or till there are no iterations
lr value in line 26 is a flash address which makes sense
My concern is that even though nextFp value is changing (confirmed by debugging), lr value is always the same flash address
Note that, this function is working fine when it gets called from a HardFault which means an exception has happened
In this case, I tried PSP and MSP instead of LR and it's now working (I don't know why though)
Could you please tell me how to enable the compiler option you mentioned? I didn't do that
2020-10-07 01:53 AM
Ohh, I only ment that there is some dereferencing needed within the loop, sorry.
Copy backtrace.c and backtrace.h files from https://github.com/red-rocket-computing/backtrace to your project and start with their ping-pong like sample.
> Could you please tell me how to enable the compiler option you mentioned?
In STM32CubeIDE: Project > Properties > C/C++ build > Setings > Tool settings
these need to be enabled: