Setting up GDB for debugging embedded devices

In this blog post, I will explain how I have set up GDB for debugging an application on STM32MP157D-DK1. Here is the remote debugging setup:

remote debugging setup overview

Table of Contents

Development workstation setup

I have set up an NFS server on my development machine as well as configured U-Boot on STM32MP157-DK1 so that any built binaries of interest on the host are easily accessible on the target machine. Also, I have set up SSH to establish a connection with the target board. For more details, check out the first two chapters of this document from Bootlin.

GDB setup for embedded systems

By its default configuration, GDB targets binaries that are being run on the same architecture as the host system GDB is running on:

using gdb for host application debugging

Screenshot captured from Memfault’s Interrupt page describing tools they use

When targeting an embedded device, GDB has to be configured in a way that it supports the target architecture of the program being debugged:

using gdb for target application debugging

Screenshot captured from Memfault’s Interrupt page describing tools they use

Binaries generated for embedded devices are often stripped of debug information to save storage space. This is also why native GDB should not be installed on an embedded target (around 2.5 MB on x86).

For that reason, remote debugging is preferred. ARCH-linux-gdb is used on the development host instead of the native GDB allowing the developer to use all features that native GDB provides. On the target side, gdbserver is used (around 400 KB on arm). It allows connecting to a fully featured remote GDB. This server handles requests from the GDB client, such as setting breakpoints, reading memory or stepping through code.

Before we start debugging, keep in mind that there are several lightweight graphical interfaces that make debugging easier. One is the default TUI that comes built-in with GDB that you enter by typing lay next when in GDB and the other is gdb-dashboard that I have just discovered recently and which I am quite fond of. It creates a .gdbinit file and populates it with sensible configuration for debugging. It enables you to use well-known shortcuts within GDB like ctrl + r for reverse searching of GDB commands you typed previously which the out-of-the-box installation of GDB does not provide. It also appends additional debug information and coloring to your console that I find quite useful.

Running ./linked_list on the target will cause a segfault. Now, let’s start the program on the target using gdbserver in multi-mode and break down what each of the commands mean:

# gdbserver --multi :2000 ./linked_list

In a separate terminal on your host machine, run export CROSS_COMPILE=/home/$USER/debugging-labs/buildroot/output/host/arm-linux-

Next, install gdb-multiarch and run gdb-multiarch ./linked_list. You have now entered GDB and inside it, run the following:

(gdb) target extended-remote 192.168.0.100:2000

NOTE: this applies if the connection with the board was established via SSH. If it was established over a serial connection, run target remote /dev/ttyUSB0, or which device it was mapped on when the board was connected to the host machine.

Finally, run:

(gdb) set sysroot /home/<user>/debugging-labs/buildroot/output/staging/

Automating repetitive tasks

Instead of retyping exact and specific commands every time you establish a connection with a target you device, you can edit your .gdbinit file which does it for you. Also, GDB has powerful Python support that it can be used to automate application debugging more efficiently by utilizing GDB’s Python API

Useful resources

A couple of useful sites I have found regarding using GDB is Jacob Sorber’s Debugging C Programs playlist, Memfault’s Interrupt GDB blogs and of course Bootlin’s Linux debugging, profiling and tracing and performance analysis training. I highly recommend you check out other topics of theirs if you are interested in embedded software development. Special thanks to Bootlin for providing the source code.

If you would like to support the work I do, consider donating here.