Recover PC From TCB

ciaranmaca wrote on Monday, April 28, 2014:

Hi All,
I have a situation where occasionally one of my tasks locks up (in the sense that it no longer hits my watchdog). I am using an older version of FreeRTOS - 6.1.0 - Cortex M3/4 Port.

I want to try to use the TCB to find where the task is stuck. My higher priority tasks come in, and one of those detects that the lower priority task is stuck (wdog monitor). In the particular task in question there is minimial use of mutexes (just one used carefully as far as I can see). So I don’t believe at this stage that it is a deadlock situation. It would be great therefore if my high priority task - which survives - could use the TCB of the stuck task to show me the PC address of the task which is stuck.

(I have no sophisticated trace tools and am not using an ETM or anything).

Thanks for your help or suggestions.

richard_damon wrote on Monday, April 28, 2014:

The definition of the TCB is intentionally hidden from user code. In your case, the simplest solution might be to copy the definition of the TCB from task.c into the file of your higher priority task, and using knowledge of the port, parse the stack pointer into a return address (you will need to look at the format of the stack frame to see how far into the stack is the return address.

You actually might want a way to get a “stack dump” for the task to get more information about what it is doing, Especially if the address it is stuck at is inside FreeRTOS.

This would normally not be advised for long term work, as you would need to manually keep track of changes in task.c and replicate them, but as a one-shot, it is workable.

dumarjo wrote on Monday, April 28, 2014:


If you are using OpenOCD as gdbserver you can add -rtos auto in your create target command from your configuration file. This will enable a special feature that will show you the state of every task you have created. This will work only if you are using the original port.

if you are not using openOCD, it more complicated to restor the context.


rtel wrote on Monday, April 28, 2014:

While it is true the definition of the TCB is deliberately hidden, if all you are looking for is the task’s stack then you can get that from the task’s handle because the task’s handle is a pointer to the task’s TCB…and the first item in the TCB is a pointer to the tasks stack.

So if you were to cast the task’s handle to a uint32_t * you would have a pointer to a pointer to the task’s stack. If you dereference that pointer you will have the task’s stack. Then you would have to work out the offset to the task’s program counter on that stack. Looking at the pxPortInitialiseStack() function in FreeRTOS/Source/portable/[compiler]/ARM_CM3/port.c file would give you a big clue as to the offset you need - looking at the file myself it seems it might be 14*4 bytes (14 unsigned longs) away from the saved value.

Once you had the program counter value you could look in the map file to see the address it relates to, or restart the application with a break point on that address, to find the line of code.

That is rather long winded and some what low level though. You might be better off starting with a newer version of FreeRTOS and defining configASSERT() to see if that finds the error for you.