Connecting GDB and gdbserver
Buildroot setup, network and serial connections, and the sysroot GDB needs to find your libraries — free linux kernel development course
With gdbserver’s role understood from the previous lecture, it’s time to actually open a debug session. This lecture in our free embedded linux course covers configuring Buildroot to build the pieces you need, connecting host GDB to target gdbserver over both a network link and a serial cable, and the single setting that trips up almost everyone on their first remote session: the sysroot.
Keywords
What You Will Learn
- Enabling cross GDB and gdbserver in Buildroot’s menuconfig
- Connecting GDB to gdbserver over TCP/IP
- Connecting over a serial (RS-232) link when no network is available
- What “sysroot” means to GDB and why remote debugging fails without it
- How Yocto and Buildroot handle sysroot differently
Prerequisites
- Completed the previous lecture on gdbserver fundamentals
- A Buildroot-based or Yocto-based target image with gdbserver installed
- Either a network path to your target or a serial console cable
Enabling GDB Support in Buildroot
Buildroot builds gdbserver for the target and, optionally, a matching cross GDB for the host, but both are off by default. If you’re using Buildroot’s internal toolchain, you need three separate options enabled in menuconfig:
BR2_PACKAGE_HOST_GDB— under Toolchain → Build cross gdb for the hostBR2_PACKAGE_GDB— under Target packages → Debugging, profiling and benchmark → gdbBR2_PACKAGE_GDB_SERVER— under Target packages → Debugging, profiling and benchmark → gdbserver
$ make menuconfig
# Toolchain ---> [*] Build cross gdb for the host
# Target packages --->
# Debugging, profiling and benchmark --->
# [*] gdbserver
# [*] gdb
$ make
Once the build finishes, your cross GDB binary lands under output/host/bin/ and gdbserver is baked into the target rootfs image.
Connecting Over a Network
With gdbserver running on the target and cross GDB available on the host, start a session by launching gdbserver first and pointing it at a TCP port to listen on:
# On the target board
# ep_sensor_reader is the program to debug
target# gdbserver :2345 ./ep_sensor_reader
Process ep_sensor_reader created; pid = 214
Listening on port 2345
You don’t need to specify an IP address unless you want to restrict which host can connect — the port number alone is usually sufficient. Next, launch your cross GDB on the host with the same binary so GDB can load the matching symbol table:
host$ arm-linux-gnueabihf-gdb ./ep_sensor_reader
Inside GDB, connect using target remote with the target’s IP and the port gdbserver is listening on:
(gdb) target remote 192.168.1.50:2345
Remote debugging using 192.168.1.50:2345
0x00007f8e1a2b6090 in ?? ()
On the target side, gdbserver confirms the connection:
Remote debugging from host 192.168.1.10
At this point you have a live remote debug session — breakpoints, stepping, and variable inspection all work as if the program were local, with the caveats covered in the previous lecture.
Connecting Over a Serial Link
When your target has no usable network connection — common during early bring-up, before a driver even exists for the network interface — gdbserver can just as easily communicate over a serial port instead of TCP. Point it at the device node for the serial interface:
# On the target board
target# gdbserver /dev/ttyS1 ./ep_sensor_reader
Serial links often need their baud rate configured explicitly first, using stty:
target# stty -F /dev/ttyS1 115200
Pick a port that isn’t already claimed by something else — in particular, avoid a port that’s serving as the system console, since gdbserver and a login shell can’t share it. On the host side, set the matching baud rate and connect to the local end of the serial cable:
(gdb) set remotebaud 115200
(gdb) target remote /dev/ttyUSB0
Everything from this point behaves identically to the network case — the transport is just a different pipe carrying the same GDB remote protocol.
Two Transports, Same Protocol
Setting the Sysroot
The single most common reason a “successful” connection still produces useless debug output is a missing sysroot. GDB needs to know where to find debug symbols and source code for shared libraries — on your development host, those paths are baked in and well known, but for a cross toolchain GDB has no way to guess the layout of the target’s root filesystem. You tell it explicitly with set sysroot.
Yocto and Buildroot expose this information in different places, because they handle library debug symbols differently.
Sysroot with the Yocto Project
Yocto includes debug information directly inside the target filesystem image, so you unpack the generated image tarball locally and point sysroot at the unpacked root:
$ mkdir ~/target-rootfs
$ cd ~/target-rootfs
$ sudo tar xf ~/poky/build/tmp/deploy/images/beaglebone/core-image-minimal-beaglebone.tar.bz2
(gdb) set sysroot /home/dev/target-rootfs
Sysroot with Buildroot
Buildroot takes a different approach: it compiles libraries with debug symbols, puts them in a staging directory, and only strips the copies that go into the actual target image. That means for Buildroot, the sysroot is always the staging area — regardless of where you extract the root filesystem itself:
(gdb) set sysroot /home/dev/buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot
Yocto vs Buildroot Sysroot at a Glance
| Build system | Where sysroot points | Why |
|---|---|---|
| Yocto Project | Unpacked target image tarball | Debug info ships inside the deployed image itself |
| Buildroot | Toolchain staging directory (output/host/.../sysroot) | Debug symbols live only in staging; target image copies are stripped |
Common Mistakes and Troubleshooting
- Forgetting
set sysrootentirely — you’ll see warnings like “Could not load shared library symbols” the moment your program touches a shared library call. - Using a serial port that’s also the console — gdbserver and getty can’t both own the port; free it up first.
- Mismatched baud rates — a serial session that connects but produces garbage almost always means host and target baud rates don’t match.
- Pointing sysroot at the wrong Buildroot directory — it must be the staging sysroot, not the final target rootfs image.
Best Practices
- Script your
set sysrootpath into a GDB command file so you never forget it — covered in the next lecture. - Prefer network debugging when available; reserve serial for early bring-up before network drivers exist.
- Keep the extracted Yocto rootfs (or Buildroot staging dir) matched to exactly the image version running on target — mismatches produce confusing symbol errors.
Summary and Key Takeaways
- Buildroot needs three explicit menuconfig options to build cross GDB and target gdbserver.
target remote IP:PORTconnects over the network;target remote /dev/ttyXplusset remotebaudconnects over serial.- GDB cannot resolve shared library symbols on a cross target without an explicit
set sysroot. - Yocto’s sysroot is the unpacked target image; Buildroot’s sysroot is always the toolchain staging directory.
Conclusion
Once you understand the connection mechanics and the sysroot requirement, opening a remote debug session becomes routine rather than mysterious. The next lecture in this free linux device drivers course turns to making that routine effortless with GDB command files, then dives into the core command set you’ll use in every session — breakpoints, stepping, and inspection commands.
FAQ
Do I always need both BR2_PACKAGE_GDB and BR2_PACKAGE_GDB_SERVER?
You need BR2_PACKAGE_GDB_SERVER on the target always. BR2_PACKAGE_GDB (native GDB on target) is optional — most workflows debug remotely from the host instead.
Why does GDB show “Could not load shared library symbols” even after connecting successfully?
You forgot set sysroot. The connection itself doesn’t require it, but resolving any shared library symbol does.
Can I use a USB-to-serial adapter for the serial connection?
Yes — that’s exactly what /dev/ttyUSB0 represents in the example; just make sure the baud rate is set to match on both ends.
Is the sysroot path the same every time I rebuild my Buildroot image?
Yes, as long as your output directory and target architecture triplet don’t change — it’s a stable staging path tied to your toolchain configuration.
What happens if I point sysroot at the wrong directory?
GDB simply won’t find matching debug symbols or source, so you’ll see the same “could not load shared library symbols” warnings as if sysroot were never set at all.
Continue the Free Embedded Systems Course
Next: GDB command files and the essential command reference.
Browse All Lectures Join EmbeddedPathashala
2 Comments