Is there a way to find out what codes/functions are running before an interrupt

Thread Starter

bug13

Joined Feb 13, 2012
1,995
Hi teams

As the title, is there a way to find out what codes/functions are running before an interrupt.

Say WDT interrupt for example. Once my WDT time out, my processor trigger an interrupt, and it pushes some registers onto the stack and jump to my WDT_ISR(). So from my WDT_ISR(), how can I find out what which function is being interrupted??

PS:
I was thinking programming in C, for AVR/PIC/MSP/STM32 MCU.
 

nsaspook

Joined Aug 27, 2009
8,685
For bare-metal without a symbolic debug runtime you might need to have global 'trace' variable(s) readable from the WDT_ISR that you could atomically set at the start of each function as a crumb trail (a simple code or ID) for were you are, as you access codes/functions. Obviously there is overhead for something like this. Normally the PC is also pushed into the stack for a possible return from interrupts or CALL instructions.
 

402DF855

Joined Feb 9, 2013
271
On some architectures the PC may be stored in a link register rather than the stack. I think the STM32, for example, might work this way.
 

ApacheKid

Joined Jan 12, 2015
418
Hi teams

As the title, is there a way to find out what codes/functions are running before an interrupt.

Say WDT interrupt for example. Once my WDT time out, my processor trigger an interrupt, and it pushes some registers onto the stack and jump to my WDT_ISR(). So from my WDT_ISR(), how can I find out what which function is being interrupted??

PS:
I was thinking programming in C, for AVR/PIC/MSP/STM32 MCU.
How do you want this to look?

Are you looking for a way to code something like this?

if (interrupted_function == SOME_FUNCTION)
; // Do X

if (interrupted_function == SOME_OTHER_FUNCTION)
; // Do Y.


and so on.

?

I will say my instincts are telling me this is not a good idea, that it can lead to unfathomable behavior and impossible to debug code, why do you need this?

Consider A calls B, then B calls C, then C calls D then the interrupt occurs and the handler runs.

Which function was interrupted? D? all of them?
 
Last edited:

Thread Starter

bug13

Joined Feb 13, 2012
1,995
For bare-metal without a symbolic debug runtime you might need to have global 'trace' variable(s) readable from the WDT_ISR that you could atomically set at the start of each function as a crumb trail (a simple code or ID) for were you are, as you access codes/functions. Obviously there is overhead for something like this. Normally the PC is also pushed into the stack for a possible return from interrupts or CALL instructions.
That's a good idea to have a global 'trace' variables. That will do what I want.

You mention "bare-metal without a symbolic debug runtime", are you suggesting we can have bare-metal with a symbolic debug runtime? If so, how can we do that?
 

Thread Starter

bug13

Joined Feb 13, 2012
1,995
On some architectures the PC may be stored in a link register rather than the stack. I think the STM32, for example, might work this way.
I don't even know what a [link register] until I google it. Is that an easy way to translate the address into function names?
 

Thread Starter

bug13

Joined Feb 13, 2012
1,995
How do you want this to look?

Are you looking for a way to code something like this?

if (interrupted_function == SOME_FUNCTION)
; // Do X

if (interrupted_function == SOME_OTHER_FUNCTION)
; // Do Y.


and so on.

?

I will say my instincts are telling me this is not a good idea, that it can lead to unfathomable behavior and impossible to debug code, why do you need this?

Consider A calls B, then B calls C, then C calls D then the interrupt occurs and the handler runs.

Which function was interrupted? D? all of them?
The reason I want to find out what codes/function are being interrupt is, I find that debugging interrupt is very hard.

A while ago I have a problem of WDT resetting the MCU in a random interval, it took me a long time to find the bug and fix it. Now the bug is fixed, I was wondering it would be great if there is a way to find out what function is being interrupted, my WDT resetting bug can be identify easily.
 

nsaspook

Joined Aug 27, 2009
8,685
That's a good idea to have a global 'trace' variables. That will do what I want.

You mention "bare-metal without a symbolic debug runtime", are you suggesting we can have bare-metal with a symbolic debug runtime? If so, how can we do that?
Your bare-metal binary could be stripped of symbols or they could be included (at the cost of flash usually) in a data segment for a debug enabled binary to use with a chips internal debug functionality and monitor devices.
https://microchipdeveloper.com/mplabx:rtdm-debugging
https://microchipdeveloper.com/mplabx:dmci-videos
 

402DF855

Joined Feb 9, 2013
271
I don't even know what a [link register] until I google it. Is that an easy way to translate the address into function names?
Not exactly. Traditionally a subroutine call or interrupt involves pushing the return address onto the stack, so that on subroutine return or return from interrupt, the processor can resume at the right spot by popping the return address off the stack. In an attempt to minimize memory accesses, some processors put the return address in a register so no memory needs be used. Now if the subroutine or interrupt service routine needs to make calls it has to save the return address away, likely to memory or possibly another register.

So on the Arm7 I recently worked on, when an exception occurred I had to examine the link register (LR) to see where the exception occurred (sometimes helpful, sometimes not). This is made complicated by the fact that there were several LRs (and SPs etc) depending on the operating mode at the time.

If you have the address of the instruction at which the interrupt occurred, the best bet is to survey the linker generated MAP file to see where it's at. Alternatively, you might look at a disassembly of the executable (ELF probably) using for example objdump.exe and find what routine is at that location.

Trying to trace backwards from that point is a bit tricky, but can be done. Look at the bottom of the stack (most recent entry) and analyze the values there and on up. Return addresses often can be picked out since your code is likely running in one or several contiguous regions, so the values may stick out. It's messy business though.

Edit: Sorry, I should have said top of the stack and work down. Stacks usually "grow" by decrementing which makes the terminology a bit confusing.
 
Last edited:

ApacheKid

Joined Jan 12, 2015
418
The reason I want to find out what codes/function are being interrupt is, I find that debugging interrupt is very hard.

A while ago I have a problem of WDT resetting the MCU in a random interval, it took me a long time to find the bug and fix it. Now the bug is fixed, I was wondering it would be great if there is a way to find out what function is being interrupted, my WDT resetting bug can be identify easily.
I suspect there's a deeper problem to solve here, what was the cause of your bug - if it can be explained easily...
 

Thread Starter

bug13

Joined Feb 13, 2012
1,995
I suspect there's a deeper problem to solve here, what was the cause of your bug - if it can be explained easily...
It was a dead lock from two different tasks. It properly caused by me not having good practice for writing code in RTOS environment, but that's a different subject that I need to work on.
 

ApacheKid

Joined Jan 12, 2015
418
It was a dead lock from two different tasks. It properly caused by me not having good practice for writing code in RTOS environment, but that's a different subject that I need to work on.
OK that's always very challenging, I'm sure you know about strategies for avoiding the possibility of deadlocks, frankly I'd advise against attempting to discover what was interrupted from within an interrupt handler. This can be done with a debugger of course nothing wrong with that, but programmatically is something I'd avoid.

I don't know much about RTOS but it there may be multiple stacks involved here, there may be a kernel mode stack and user mode stacks for example.

The stack that's active within an interrupt handler might not be the same stack user code uses, this can all be quite non-intuitive and assuming too much might lead to serious bewilderment!
 
Top