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
GDB server listening on port 3333
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"
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_boot.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).