Using GDB with GDB Server within Visual Studio Code

This post walks through a simple setup and usage of the gdb with gdbserver for Visual Studio Code for debugging a program running on a remote embedded target from a host PC.

One should read this post first before starting this one.

Setting Up Tasks to Build the Needed Binaries

VSCode Tasks allows one to integrate custom commands and external tools into the VSCode editor. For detailed information about creating and using tasks in VSCode, visit the VSCode site and also Stack Overflow. Two tasks are needed for this effort:

  1. A task to produce the program for the target with debug information and no optimizations
  2. A task to produce a fully stripped program for the target with no debug information and no optimizations

I have a Bash shell script for kicking off the CMake build process producing different variants of the program given different arguments, one only needs to write the tasks to invoke the script the same way one would do manually. A tasks.json file was created inside the .vscode folder in the project’s root folder. The following JSON lines were inserted in the tasks.json file to produce the debug variant for the target:

{
    "label": "Build embedded application with debug information",
    "command": "./build.sh",
    "args": [
        "arm",
        "debug"
    ],
    "problemMatcher": [],
    "presentation": {
        "echo": true,
        "reveal": "silent",
        "focus": false,
        "panel": "shared",
        "clear": false,
        "revealProblems": "onProblem",
        "close": true
    }
},

The task for producing the fully stripped version with no optimizations is trivially similar:

{
    "label": "Build embedded application with no optimizations",
    "command": "./build.sh",
    "args": [
        "arm"
    ],
    "problemMatcher": [],
    "presentation": {
        "echo": true,
        "reveal": "silent",
        "focus": false,
        "panel": "shared",
        "clear": false,
        "revealProblems": "onProblem",
        "close": true
    }
},

Using the [Shift]+[Ctrl]+[P] combination on the keyboard to reveal the command menu, I ran both tasks to verify successful integration with VSCode and that the programs for each were produced with no issues. In addition, a task to remove build artifacts was also added and verified for successful integration:

{
    "label": "Remove all build artifacts",
    "command": "./clean.sh",
    "problemMatcher": [],
    "presentation": {
        "echo": true,
        "reveal": "silent",
        "focus": false,
        "panel": "shared",
        "clear": false,
        "revealProblems": "onProblem",
        "close": true
    }
},

Setting Up a Launch Configuration for GDB

In order to invoke gdb from within VSCode, a launch configuration file needs to exists. For detailed information about launch configurations please visit the VSCode site. Create a launch.json file in the .vscode folder if one does not already exist. I put the following JSON lines into the file configuration and invocation of gdb:

"configurations": [
    {
        "name": "GDB for BBB (ARM) Remote Attach",
        "type": "cppdbg",
        "request": "launch",
        "externalConsole": false,
        "stopAtEntry": true,
        "program": "${workspaceFolder}/_Deployment/armv7/debug/xmbedApp",
        "MIMode": "gdb",
        "cwd": "${workspaceFolder}",
        "miDebuggerPath": "/opt/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-gdb",
        "miDebuggerServerAddress": "192.168.0.6:2345",
        "miDebuggerArgs": " -ex 'handle all print nostop noignore'",
        "setupCommands": [
            {
                "description": "Enable pretty-printing for gdb",
                "text": "-enable-pretty-printing",
                "ignoreFailures": true
            }
        ],
        "preLaunchTask": "Build embedded application with debug information"
    }
]

Looking at the miDebuggerPath variable, its value is the path to the gdb program associated with the ARM GCC toolchain. Since we will be connecting to gdbserver running on the target, the IP address with port is also provided in the launch configuration. The path to the debug variant of our custom program on the host PC is specified. The configuration file also includes a pre-launch task to build the debug variant of the program for the target before launching gdb.

Running GDB

In a separate terminal window, tunnel into the target via ssh. Navigate to the location of the custom program, and start gdbserver passing the name of the application as an argument:

gdbserver ip-address:port program-name

In my case, the command looked like this:

gdbserver :2345 xmbedApp

In VSCode, click the ‘Run and Debug’ button (1) on the left-most side of the window or press [Ctrl]+[Shift]+[P] on the keyboard. Click the green arrow (2) or press [F5] to start gdb with the launch configuration we setup earlier:

Run and debug

The debugging session will start, and one can then set breakpoints, examine variables, and other functionality associated with using GDB. Below is a screenshot for an example programing using gdb/gdbserver with VSCode:

On the left is the VSCode editor and on the right is the terminal window for the remote target running our program with gdbserver.