Longan Nano : FreeRTOS Thread support within GDB

 

This is a common need: Be able to see and navigate among threads from gdb.
There are 2 ways to do that :
  1. It is built-in at  low level. That means either inside gdb or openOcd or blackmagic probe etc....
  2. Using external scripts
One gotcha to make things more difficult : Depending on the FreeRTOS port, the way the registers are pushed on the stack differs and may confuse gdb.

As far as option 1 is concerned,  i did not manage to make it work with riscv-openOCD, in addition i'm pretty sure the FreeRTOS port i'm using will cause problem

So let's go for option 2.

GDB Python support 

We'll use some python3 scripts within gdb to deal with thread awareness
In order to do that, we'll need a python3 enabled riscv gdb
Let's download the vanilla gdb 10.2 from gnu.org  (*not* the riscv version) and configure it that way

export PATH=/opt/gd32/toolchain/bin/:$PATH

echo /usr/bin/python3-config --includes
echo /usr/bin/python3-config --libs

export PYVER=3.8

export LIBS=`/usr/bin/python3-config --libs`
export LDFLAGS=`/usr/bin/python3-config --ldflags`
export CFLAGS=`/usr/bin/python3-config --includes`
make clean
./configure --prefix=/opt/gd32/riscv_gdb \
    --target=riscv32-unknown-elf \
    --with-abi=ilp32 --disable-multilib \
   --disable-ada \
   --disable-objc-gc \
   --with-python=/usr/bin/python${PYVER}  
make -j 4
make install

Dont forget to install python3-dev or whatever the name is on your system

Let's check if it worked :

ldd /opt/gd32/riscv_gdb/bin/riscv32-unknown-elf-gdb | grep python
    libpython3.8.so.1.0 => /lib/x86_64-linux-gnu/libpython3.8.so.1.0 

Looks good

Add some commands to gdb with python

So now checkout the modified FreeRTOS-GDB from git@github.com:mean00/FreeRTOS-GDB.git

MAKE SURE YOU ARE USING THE GD32 BRANCH

Good, now let's invoke it from gdb

source /opt/gd32/FreeRTOS-GDB-GD32/src/FreeRTOS.py

Using

run your program, stop gdb


gdb) show Task-List  
0   TCB: 0x20001320 Name:   entryTask State:Delay1 TopOfStack:0x20001230
                 PC=0x80073a4 SP=0x200012c0 function=vPortSetMSIPInt
1 * TCB: 0x20001588 Name:        IDLE  
2   TCB: 0x20001d20 Name:     Tmr Svc State:Blked  TopOfStack:0x20001c30
                 PC=0x80073a4 SP=0x20001cc0 function=vPortSetMSIPInt

Ok, let's see what thread 2 is doing

(gdb) switchTCB 2
switch TCB 2  
(gdb) bt
#0  0x080057ae in prvIdleTask (pvParameters=<optimized out>) at /home/fx/Arduino_gd32/hello2/Arduino_gd32_freeRTOS/FreeRTOS/tasks.c:3470
#1  0xa5a5a5a5 in ?? ()

That does not look good 

The problem is that the switch occurs with the sofware interrupt :

- Only mepc is changed

- The stack contins the software interrupt registers stacking


ReturnFromException


To deal with that, let's add a "ReturnFromException" helper function that will copy mpec to pc and pop out the registers


(gdb) ReturnFromException  
(gdb) bt
#0  vPortSetMSIPInt () at /home/fx/Arduino_gd32/hello2/Arduino_gd32_freeRTOS/freeRTOS_extension/N200/port.c:121
#1  0x08006fe0 in prvProcessTimerOrBlockTask (xListWasEmpty=<optimized out>, xNextExpireTime=<optimized out>) at /home/fx/Arduino_gd32/hello2/Arduino_gd32_freeRTOS/FreeRTOS/timers.c:642
#2  prvTimerTask (pvParameters=<optimized out>) at /home/fx/Arduino_gd32/hello2/Arduino_gd32_freeRTOS/FreeRTOS/timers.c:588
#3  0x08007300 in xTimerPendFunctionCall (xFunctionToPend=<optimized out>, pvParameter1=<optimized out>, ulParameter2=<optimized out>, xTicksToWait=<optimized out>)
   at /home/fx/Arduino_gd32/hello2/Arduino_gd32_freeRTOS/FreeRTOS/timers.c:1086

Much better !


Please note that the script is for postmortem analysis. You cannot really resume operations once you have messed with the exception.






Comments

Popular posts from this blog

Component tester with STM32 : Part 1 ADC, Resistor

Fixing the INA3221

INA3221, weird wiring