Using GDB and GDB Server with the Beaglebone Black

This post is a “quick and dirty” for using GDB and GDB server on the command line with the Beaglebone Black (BBB) Single Board Computer (SBC).

Host and Target Environments

ItemHostTarget
MachineCustom-built PCBeaglebone Black (BBB) Single-board Computer (SBC)
Operating SystemLinux Mint 21.1 Vera, 5.15.0-91-generic #101-Ubuntu SMP Tue Nov 14 13:30:08 UTC 2023 x86_64 GNU/LinuxDebian Linux with TI BSP, 5.10.168-ti-rt-r74 #1bookworm SMP PREEMPT_RT Sun Dec 17 03:43:27 UTC 2023 armv7l GNU/Linux
System Memory32 GB512 MB
Storage3 TB4 GB eMMC (using 128 GB SDCard)
ProcessorIntel© Core™ i7-8700K CPU @ 3.70GHz × 6TI Sitara AM3358BZCZ100 ARM Cortex-8 @ 1GHz
# of cores61
GCC Toolchaingcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0arm-none-linux-gnueabihf-gcc (Arm GNU Toolchain 12.2.Rel1 (Build arm-12.24)) 12.2.1 20221205

Required Software Tools

For the host PC, the required GDB binary is packaged with the ARM GCC Toolchain. Download the toolchain and install it to a directory of your choosing. The writer of this document is using the previously detailed ARM GNU Toolchain installed in the /opt folder. For the target, use SSH to tunnel into the target system and verify that GDB server is installed. If the binary is not installed, install it using the following command (or similar command with your package manager):

sudo apt install gdbserver

Building the Needed Binary for the Target

Using GDB server on the embedded target, a program containing debugging symbols is not required. One can (and should) fully strip the program to save space. What should be done, is to pass in the right flags to the compiler during the build process. Here is a snippet from my own top-level CMakeLists.txt file:

...
if ( CMAKE_CROSSCOMPILING AND CMAKE_BUILD_TYPE STREQUAL "Release" )
    set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os -s" )
    set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -s" )
else()
    set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g" )
    set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g" )
endif()
...

The CMAKE_BUILD_TYPE variable only has two values, “Release” or “Debug”. The value of this variable determines if the binary will contain information for aiding debug sessions or if the binary will be stripped of all that information and be as small as possible regardless of target.

The following Bash shell script is used to invoke the CMake build process given specific arguments:

#!/bin/bash

# print options and exit
function print_help()
{
    printf "Usage: ./build.sh [OPTION]\n"
    printf "Options:\n"
    printf "%s\tShow options and exit.\n" "-h"
    printf "%s\tBuild debug version of the application for the desktop.\n" "-d"
    printf "%s\tBuild release version of the application for BBB\n" "-a"
    printf "%s\tBuild debug version of the application for BBB\n" "-b"
    printf "%s\tRemove build artifacts\n" "-c"
}

BUILD_DIR=_Build
DEPLOY_DIR=_Deployment

if [[ "$1" == "-h" ]]; then
    print_help
    exit 0
elif [[ "$1" == "-c" ]]; then
    # remove the build and deployment folders
    rm -rf $BUILD_DIR $DEPLOY_DIR
    # clean submodule directory
    cd XmbedMessage
    ./clean.sh
    exit 0
fi

if [[ "$1" == "-d" ]] || [[ "$1" == "-a" ]] || [[ "$1" == "-b" ]]; then
    # create build directory
    mkdir -p $BUILD_DIR
    # go into the build directory
    cd $BUILD_DIR
    if [[ "$1" == "-d" ]]; then
        # debug configuration for desktop
        cmake -DCMAKE_BUILD_TYPE=Debug -G Ninja ..
    elif [[ "$1" == "-a" ]]; then
        cmake -DCMAKE_TOOLCHAIN_FILE:PATH="..\toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -G Ninja ..
    else
        cmake -DCMAKE_TOOLCHAIN_FILE:PATH="..\toolchain.cmake" -DCMAKE_BUILD_TYPE=Debug -G Ninja ..
    fi
else
    print_help
    exit 0
fi
# build the software products
cmake --build . -j $(nproc)

To build the program needed for the target, we invoke the script in the following manner:

./build.sh -a

The toolchain.cmake file provides setup parameters for the CMake build system to use with the GCC ARM toolchain to cross-compile the code for targeting the BBB. This will not be covered here and one is encouraged to use a search engine to find the ample examples of CMake toolchain files online.

Once compilation is complete, copy the program to the target (here we use ‘rsync’):

rsync -av -e ssh path/to/program username@ip-address:/path/to/directory

For the writer’s project setup the command looks like this:

rsync -av -e ssh _Deployment/app/release/xmbedApp username@ip-address:/path/to/home

Type in the required password if prompted and the transfer should complete shortly.

Compiling the program for Host-side GDB Consumption

We need a version of our custom program with debugging symbols for consumption by GDB on the host side. To get this program, we build using the following command:

./build.sh -b

Earlier, a snippet of the top-level CMakeLists.txt file was provided. In there, one can see that debug flags ‘-O0 -g’ are passed to the compiler. Again, the ‘-O0’ flag tells the compiler to disable any optimizations, but the additional ‘-g’ flag tells the compiler to generate debug symbols in the system’s native format and compile them into the program. Since we are cross-compiling, the debug symbols will be in the target’s native format (whatever that is).

Connecting GDB Host-side with Target-side GDB Server

Open a second terminal window and tunnel into the target via ‘SSH’. Navigate to the directory containing our program. The GDB server program is invoked in the following manner:

gdbserver ip-address:port path/to/program

Since we are running the server on the target, we can omit the ip-address and just start the server with a port number and pass in the name of our custom program as an argument:

gdbserver :2345 program

The Server will wait and listen for a connection and commands from the host PC (example view from BBB in terminal):

debian@BeagleBone:~$ gdbserver :2345 xmbedApp 
Process /home/debian/xmbedApp created; pid = 1237
Listening on port 2345

NOTE: Word to the wise, one cannot ‘Ctrl+C’ out of gdbserver while waiting for the host connection, one will have to power-cycle the target board to break out.

On the host side, use the GDB program packaged with the ARM GCC toolchain passing in the path to the previously compiled program as an argument:

/path/to/ARM-GCC-toolchain-GDB /path/to/debug-binary

The writer of this document has created a symbolic link to the required GDB program and named it ‘gdb-arm’. So for our example here GDB on the host is invoked this way:

gdb-arm _Deployment/app/debug/xmbedApp 

Connect to the target with the following command within GDB:

(gdb) target remote ip-address:port

where ‘ip-address’ is the network address of the target and ‘port’ is the GDB Server listening port given earlier. For the setup used by the writer, the command would look like this:

(gdb) target remote 192.168.0.6:2345

Once GDB on the host side connects to the target side, the terminal window for the target should indicate the host is connected:

Remote debugging from host ::ffff:192.168.0.2, port 46328

Setup with GDB

GDB needs to know where to find the code files associated with our program, direct GDB to the root location by issuing the following command:

(gdb) dir /path/to/code-root-folder

For example, if GDB was invoked from within the project’s root folder as is the case for the writer of this document, one can simply type this:

(gdb) dir ./

Next, we need to give GDB the system root location on the target, do so by typing the following:

(gdb) set sysroot target:/

Time to Debug

Our example program is very simple containing the following lines in main.cpp:

Now, let us set one break point using the ‘break’ (‘b’) command:

(gdb) break main.cpp:16

GDB does not support the ‘run’ (‘r’) command for remote debugging sessions, we must start debug session on the target by issuing the ‘continue’ (‘c’) command:

(gdb) c

GDB on the target will run the program and halt at the first set break point. For this example, the writer chose to step through until the end by issuing the ‘next’ (‘n’) command:

Breakpoint 1, main (argc=1, argv=0xbefff714) at /home/bdn/Programming/Beaglebone/app/main.cpp:16
16	    std::cout << "Hello world!" << std::endl;
(gdb) n
17	    std::cout << "I feel useful" << std::endl;
(gdb) n
18	    std::cout << "Good bye" << std::endl;
(gdb) n
19	    return 0;
(gdb) n
20	}
(gdb) n
0xb6ce45a0 in __libc_start_main () from target:/lib/arm-linux-gnueabihf/libc.so.6
(gdb) n
Single stepping until exit from function __libc_start_main,
which has no line number information.
[Inferior 1 (process 1785) exited normally]

We display the print out from the target side terminal window for the debugging session:

debian@BeagleBone:~$ gdbserver :2345 xmbedApp 
Process /home/debian/xmbedApp created; pid = 1237
Listening on port 2345
Remote debugging from host ::ffff:192.168.0.2, port 46328
Hello world!
I feel useful
Good bye

Child exited with status 0

This walk-through is far from perfect and the reader is encouraged to conduct more research on using GDB and GDB server on his or hers own time.

Appendix

The following section contains the entire host-side terminal output for the GDB remote debug session for completeness.

bdn@Sonora2:~/Programming/Beaglebone(develop)$ gdb-arm _Deployment/app/debug/xmbedApp 
GNU gdb (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16)) 10.1.90.20201028-git
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=arm-none-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://bugs.linaro.org/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from _Deployment/app/debug/xmbedApp...
(gdb) target remote 192.168.0.6:2345
Remote debugging using 192.168.0.6:2345
Reading symbols from /opt/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/arm-none-linux-gnueabihf/libc/lib/ld-linux-armhf.so.3...
0xb6fd5a80 in _dl_start_user () from /opt/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/arm-none-linux-gnueabihf/libc/lib/ld-linux-armhf.so.3
(gdb) dir ./
Source directories searched: /home/bdn/Programming/Beaglebone:$cdir:$cwd
(gdb) set sysroot target:/
Reading /lib/ld-linux-armhf.so.3 from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /lib/ld-linux-armhf.so.3 from remote target...
warning: .dynamic section for "target:/lib/ld-linux-armhf.so.3" is not at the expected address (wrong library or version mismatch?)
Reading symbols from target:/lib/ld-linux-armhf.so.3...
Reading /lib/17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading /lib/.debug/17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading /usr/lib/debug//lib/17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading /usr/lib/debug/lib//17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading target://usr/lib/debug/lib//17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
(No debugging symbols found in target:/lib/ld-linux-armhf.so.3)
Reading /lib/ld-linux-armhf.so.3 from remote target...
Reading /lib/ld-linux-armhf.so.3 from remote target...
Reading symbols from target:/lib/ld-linux-armhf.so.3...
Reading /lib/17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading /lib/.debug/17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading /usr/lib/debug//lib/17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading /usr/lib/debug/lib//17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
Reading target://usr/lib/debug/lib//17f0bca2ae53f327681aa4c81f6d849c5d5fe2.debug from remote target...
(No debugging symbols found in target:/lib/ld-linux-armhf.so.3)
(gdb) break main.cpp:16
Breakpoint 1 at 0x1071e: file /home/bdn/Programming/Beaglebone/app/main.cpp, line 16.
(gdb) c
Continuing.
Reading /usr/lib/arm-linux-gnueabihf/libatomic.so.1 from remote target...
Reading /usr/lib/arm-linux-gnueabihf/libstdc++.so.6 from remote target...
Reading /lib/arm-linux-gnueabihf/libm.so.6 from remote target...
Reading /lib/arm-linux-gnueabihf/libgcc_s.so.1 from remote target...
Reading /lib/arm-linux-gnueabihf/libpthread.so.0 from remote target...
Reading /lib/arm-linux-gnueabihf/libc.so.6 from remote target...
Reading /usr/lib/arm-linux-gnueabihf/792ecf1710c7a0a6819a5afaadc9477511aa5b.debug from remote target...
Reading /usr/lib/arm-linux-gnueabihf/.debug/792ecf1710c7a0a6819a5afaadc9477511aa5b.debug from remote target...
Reading /usr/lib/debug//usr/lib/arm-linux-gnueabihf/792ecf1710c7a0a6819a5afaadc9477511aa5b.debug from remote target...
Reading /usr/lib/debug/usr/lib/arm-linux-gnueabihf//792ecf1710c7a0a6819a5afaadc9477511aa5b.debug from remote target...
Reading target://usr/lib/debug/usr/lib/arm-linux-gnueabihf//792ecf1710c7a0a6819a5afaadc9477511aa5b.debug from remote target...
Reading /usr/lib/arm-linux-gnueabihf/e6afe7412e5771fcd3e4bc2ac075e0021b2d80.debug from remote target...
Reading /usr/lib/arm-linux-gnueabihf/.debug/e6afe7412e5771fcd3e4bc2ac075e0021b2d80.debug from remote target...
Reading /usr/lib/debug//usr/lib/arm-linux-gnueabihf/e6afe7412e5771fcd3e4bc2ac075e0021b2d80.debug from remote target...
Reading /usr/lib/debug/usr/lib/arm-linux-gnueabihf//e6afe7412e5771fcd3e4bc2ac075e0021b2d80.debug from remote target...
Reading target://usr/lib/debug/usr/lib/arm-linux-gnueabihf//e6afe7412e5771fcd3e4bc2ac075e0021b2d80.debug from remote target...
Reading /lib/arm-linux-gnueabihf/ad7a330dfc613be2732c15f4b9e439e0742b50.debug from remote target...
Reading /lib/arm-linux-gnueabihf/.debug/ad7a330dfc613be2732c15f4b9e439e0742b50.debug from remote target...
Reading /usr/lib/debug//lib/arm-linux-gnueabihf/ad7a330dfc613be2732c15f4b9e439e0742b50.debug from remote target...
Reading /usr/lib/debug/lib/arm-linux-gnueabihf//ad7a330dfc613be2732c15f4b9e439e0742b50.debug from remote target...
Reading target://usr/lib/debug/lib/arm-linux-gnueabihf//ad7a330dfc613be2732c15f4b9e439e0742b50.debug from remote target...
Reading /lib/arm-linux-gnueabihf/b55e299e787b32133eaea00cf280dc84215770.debug from remote target...
Reading /lib/arm-linux-gnueabihf/.debug/b55e299e787b32133eaea00cf280dc84215770.debug from remote target...
Reading /usr/lib/debug//lib/arm-linux-gnueabihf/b55e299e787b32133eaea00cf280dc84215770.debug from remote target...
Reading /usr/lib/debug/lib/arm-linux-gnueabihf//b55e299e787b32133eaea00cf280dc84215770.debug from remote target...
Reading target://usr/lib/debug/lib/arm-linux-gnueabihf//b55e299e787b32133eaea00cf280dc84215770.debug from remote target...
Reading /lib/arm-linux-gnueabihf/f5f6b192d7c804b0acd47bfb1c617d6ec3849a.debug from remote target...
Reading /lib/arm-linux-gnueabihf/.debug/f5f6b192d7c804b0acd47bfb1c617d6ec3849a.debug from remote target...
Reading /usr/lib/debug//lib/arm-linux-gnueabihf/f5f6b192d7c804b0acd47bfb1c617d6ec3849a.debug from remote target...
Reading /usr/lib/debug/lib/arm-linux-gnueabihf//f5f6b192d7c804b0acd47bfb1c617d6ec3849a.debug from remote target...
Reading target://usr/lib/debug/lib/arm-linux-gnueabihf//f5f6b192d7c804b0acd47bfb1c617d6ec3849a.debug from remote target...
Reading /lib/arm-linux-gnueabihf/7e3cad4070da5965d7c8ba10334e9058d0eb60.debug from remote target...
Reading /lib/arm-linux-gnueabihf/.debug/7e3cad4070da5965d7c8ba10334e9058d0eb60.debug from remote target...
Reading /usr/lib/debug//lib/arm-linux-gnueabihf/7e3cad4070da5965d7c8ba10334e9058d0eb60.debug from remote target...
Reading /usr/lib/debug/lib/arm-linux-gnueabihf//7e3cad4070da5965d7c8ba10334e9058d0eb60.debug from remote target...
Reading target://usr/lib/debug/lib/arm-linux-gnueabihf//7e3cad4070da5965d7c8ba10334e9058d0eb60.debug from remote target...

Breakpoint 1, main (argc=1, argv=0xbefff714) at /home/bdn/Programming/Beaglebone/app/main.cpp:16
16	    std::cout << "Hello world!" << std::endl;
(gdb) n
17	    std::cout << "I feel useful" << std::endl;
(gdb) n
18	    std::cout << "Good bye" << std::endl;
(gdb) n
19	    return 0;
(gdb) n
20	}
(gdb) n
0xb6ce45a0 in __libc_start_main () from target:/lib/arm-linux-gnueabihf/libc.so.6
(gdb) n
Single stepping until exit from function __libc_start_main,
which has no line number information.
[Inferior 1 (process 1237) exited normally]