Question

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 ;

}
Was it helpful?

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.

OTHER TIPS

ARM defines a pair of sections, .ARM.exidx and .ARM.extbl, that contain enough information to unwind the stack without debug symbols. These sections exist for exception handling but you can use them to perform a backtrace as well. Add -funwind-tables to force GCC to include these sections.

Did I hear my name? :)

You will probably need a tiny bit of inline assembly. Just figure out the format of the stack frames, and which register holds the ordinary1 stack pointer, and transfer the relevant values into C variables from which you can format strings for output to the UART.

It shouldn't be too tricky, but of course (being rather low-level) you need to pay attention to the details.

1As in "non-exception"; not sure if the ARM has different stacks for ordinary code and exceptions, actually.

To do this with ARM, you will need to tell your compiler to generate stack frames. For instance with gcc, check the option -mapcs-frame. It may not be the one you need, but this will be a start.

If you do not have this, it will be nearly impossible to "unroll" the stack, because you will need for each function the exact stack usage depending on parameters and local variables.

If you are looking for some exemple code, you can check dump_stack() in Linux kernel sources, and find back the related piece of code executed for ARM.

Your watchdog timer can fire at any point, even when the stack does not contain enough information to unwind (e.g. stack space has been allocated for register spill, but the registers not copied yet).

For properly optimized code, you need debug info, period. All you can do from a watchdog timer is a register and stack dump in a format that is machine readable enough to allow conversion into a core dump for gdb.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top