carmstack-tracecortex-miar

call stack unwinding in ARM cortex m3


I would like to create a debugging tool which will help me debug better my application. I'm working bare-bones (without an OS). using IAR embedded workbench on Atmel's SAM3.

I have a Watchdog timer, which calls a specific IRQ in case of timeout (This will be replaced with a software reset on release). In the IRQ handler, I want to print out (UART) the stack trace, of where exactly the Watchdog timeout occurred.

I looked in the web, and I didn't find any implementation of that functionality.

Anyone has an idea on how to approach this kind of thing ?

EDIT: OK, I managed to grab the return address from the stack, so I know exactly where the WDT timeout occurred. Unwinding the whole stack is not simple as it first appears, because each function pushes different amount of local variables into the stack.

The code I end up with is this (for others, who may find it usefull)

void WDT_IrqHandler( void )
{
    uint32_t * WDT_Address;
    Wdt *pWdt = WDT ;
    volatile uint32_t dummy ;
    WDT_Address = (uint32_t *) __get_MSP() + 16 ;
    LogFatal ("Watchdog Timer timeout,The Return Address is %#X", *WDT_Address);
    /* Clear status bit to acknowledge interrupt */
    dummy = pWdt->WDT_SR ;

}

Solution

  • It should be pretty straight forward to follow execution. Not programmatically in your isr...

    We know from the ARM ARM that on a Cortex-M3 it pushes xPSR, ReturnAddress, LR (R14), R12, R3, R2, R1, and R0 on the stack. mangles the lr so it can detect a return from interrupt then calls the entry point listed in the vector table. if you implement your isr in asm to control the stack, you can have a simple loop that disables the interrupt source (turns off the wdt, whatever, this is going to take some time) then goes into a loop to dump a portion of the stack.

    From that dump you will see the lr/return address, the function/instruction that was interrupted, from a disassembly of your program you can then see what the compiler has placed on the stack for each function, subtract that off at each stage and go as far back as you like or as far back as you have printed the stack contents.

    You could also make a copy of the stack in ram and dissect it later rather than doing such things in an isr (the copy still takes too much time but is less intrusive than waiting on the uart).

    If all you are after is the address of the instruction that was interrupted, that is the most trivial task, just read that from the stack, it will be at a known place, and print it out.