Debugging an application with GDB

Note

  • On board, cluster debugging is not yet available but will be in a future release.

  • Debugging will not work if your application performs actions that might disable the JTAG connection (deep sleep as an example). To debug such applications please remove all such actions.

Prerequisites

To be able to debug your application, you will need to obtain a recent GDB from the official RISC-V GNU toolchain. You can find it here: https://github.com/riscv-collab/riscv-gnu-toolchain. It is possible to either compile it following the README there or to download a precompiled toolchain from the release page. Once acquired, either by compiling or downloading, please install/unpack it in a known location. In this guide, it will be assumed that you used the XDG standard user directory ~/.local/bin or another directory covered by your $PATH environment variable. This way, you may access GDB using riscv64-unknown-elf-gdb directly. Also note that only GDB should be used from that toolchain, please continue to use the toolchain provided by GreenWaves Technologies for code compilation as otherwise you will encounter severe performance regressions.

Using GDB to debug your application

GDB is enabled with the option CONFIG_GDB_SERVER.

When running your app, you should see:

Ready for Remote Connections

This means a GDB server, connected to your board (or to your GVSoC proxy) is now active on port localhost:3333. Another GDB port can be specified with the option CONFIG_GDB_SERVER_PORT=3333.

Now, in another terminal, execute the following command (assuming your application is named test):

riscv64-unknown-elf-gdb build/test

This will open a GDB prompt. You can now enter the following GDB commands:

(gdb) target remote :3333
(gdb) load

You should see a message about code sections loading. This means that your application binary is now loaded.

You may now use regular GDB features such as breakpoints. Once you have setup your breakpoints, you can run with continue.

If you need to reset the board use monitor reset halt and then load again.

Setting up debug for a flash booted application

In order to debug an application that has been booted from flash, two solutions exist. The first one is a simple live JTAG connection, without resetting. This will allow to connect either gdb or telnet to a live running application. The second is to simulate the flash boot process, but with JTAG, then connect GDB.

The advantage of the second solution is that it allows better control of the application, as the debugger should be able to take control of said application much earlier. Conversely, the first solution has the advantage of being the least intrusive.

In both cases, it is required to first prepare boot from flash as usual, and then run a manual openocd command to connect.

openocd -d0 -c "gdb_port 3333; telnet_port 6666; tcl_port disabled" -f "${GAP_SDK_HOME}/utils/openocd_tools/tcl/gapuino_ftdi.cfg" -f "${GAP_SDK_HOME}/utils/openocd_tools/tcl/gap9revb_mram_connect.tcl"

In both cases, the cable part (gapuino_ftdi.cfg script) may need to be adapted to the actual JTAG cable being used. Also gdb_port must be set to desired port to use GDB. In the same way, the telnet_port is required if telnet debug is desired.

After this, GDB can be launched as above to debug the application.

Debugging with FreeRTOS

Packages exist to help with debugging FreeRTOS or multi thread related problems. One that is currently recommended is freertos_gdb. You may install it with pip install freertos_gdb. Using is fairly straightforward, after start gdb normally, simply type python import freertos_gdb.

At that point simply type freertos to get an help on available commands. Task debugging is automatically available, only action that may be required if for semaphores and queues. Those indeed need to be registered, which is done as follows (works for Queues, Semaphores and Mutexes):

vQueueAddToRegistry(my_semaphore, "My sempahore");

This will make the semaphore my_semaphore visible as My semaphore in the semaphore debug panel of freertos_gdb. On system level, ticking the Register semaphore (debug) option in Utils->debug menu will register all semaphores used for internal needs (printf, cluster etc).