cancel
Showing results for 
Search instead for 
Did you mean: 

unwind the stack in non-exception

AAl-H.1
Associate II

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);
}

12 REPLIES 12
KnarfB
Principal III

line 31 nextFp = nextFp + 4; look suspicious. Needs a pointer dereferencing.

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

I've changed line 31 to this:

nextFp = *((uint32_t*)nextFp + 4);

But now I'm getting 0 except for the first iteration

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?

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

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).

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):

https://patchwork.ozlabs.org/project/gcc/patch/20180827093530eucas1p2c931fb7d5bc0a73d2b657116b0288e1b~OtBY8cdXJ0574305743eucas1p2z@eucas1p2.samsung.com/

Here is an interesting approach using debug info: https://github.com/red-rocket-computing/backtrace

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

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:

0693W000004IuWFQA0.png