Published on

VSCode GDB 远程调试

Authors

需求

开发环境和程序实际运行环境不一样,又需要调试时,可以使用 GDB 远程调试。

例如我在 x86 上开发,在嵌入式 arm 板上运行程序,又或者单纯的想在 Windows 上开发,放到 Ubuntu 上运行,这些情况调试时都可以使用 gdb 进行远程调试。

基本原理

在远端(即需要运行程序的机器上)用gdbserver启动待调试程序,并监听指定端口。

在本地(即开发程序的机器上)用相应版本的 gdb连接远端 gdbserver 进行调试。

gdbserver + gdb 调试

所需工具:

工具功能
gnu-gcc编译可在目标远程机器上运行的程序。
gnu-g++编译可在目标远程机器上运行的程序。
gnu-strip通常编译时,使用-g添加调试符号用于调试,但该运行程序体积较大,gnu-strip可以删除调试符号,生成体积较小的发布版本。
gdbserver运行在目标远程机器上,用于启动调试服务。
gnu-gdb用于连接远程机器上的 gdbserver。

这些工具应保持版本一致

具体步骤:

  1. 目标远程机器上执行

    # cd到要运行的程序目录下
    $ cd /mnt/adas-rt/
    # 启动调试服务,端口号2333按实际工作环境指定
    $ gdbserver localhost:2333 ./hobot-adas-workflow config/global.json 1
    # 服务启动成功
    Listening on port 2333
    

    编译时需要编译两个可执行文件:

    1. hobot-adas-workflow:删除调试符号版本,文件体积较小,上传到远端;
    2. hobot-adas-workflow.gdb:带调试符号版本,文件体积很大,保留在本地。
  2. 本地机器执行

    # cd到与编译所使用的gdb工具链目录下
    $ cd toolchain/bin
    # 启动对应的gdb工具,而非默认gdb,并指定带有调试符号的可执行程序
    $ ./aarch64-linux-gnu-gdb hobot-adas-workflow.gdb
    # 先指定本地机器代码目录,不指定将在运行时自动寻找,速度较慢
    (gdb) set sysroot ~/SrcCode/
    # 连接到目标远程机器上的调试服务,remote_ip:port按实际工作环境指定
    (gdb) target remote remote_ip:port
    # 指定断点
    (gdb) break main
    # 开始运行(要使用continue而不是run,可能是gdb版本原因)
    (gdb) c
    # 运行一段时间后,成功命中断点
    Breakpoint 1, main (argc=3, argv =0x7ffffffc18) at ~/SrcCode/main.cpp:18
    18 int main(int argc, char **argv) {
    

参考链接:gdb-remote-debugging-cant-seem-to-find-symbols

VSCode 配置

单纯使用 gdb 进行调试很不方便。接下来配置 VSCode,使用 VSCode 进行远程调试。

初步配置

使用 VSCode 打开工程文件夹,注意目录地址,指定不正确(如选择了父目录或子目录)将无法命中断点

.vscode目录下新建 launch.json,内容如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb)Launch",
      "type": "cppdbg",
      "request": "launch",
      // 指定带调试符号的可执行程序
      "program": "build/hobot-adas-workflow.gdb",
      "args": [],
      "stopAtEntry": false,
      // 当前工作环境
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      // 指定GDB调试工具
      "miDebuggerPath": "~/SrcCode/toolchain/bin/aarch64-linux-gnu-gdb",
      // 目标远程机器服务地址
      "miDebuggerServerAddress": "remote_ip:port"
    }
  ]
}

在代码中打好断点,按F5就可以愉快的调试啦~

全流程自动化

不太好的一点是,上述操作每次都需要在目标远程机器上启动服务,调试结束后服务会自动结束,下次调试需要重新启动服务。

接下来在 VSCode 中增加一个自动启动远程服务的命令。

launch.json 中新增两行:

// 开始调试前要执行的任务
"preLaunchTask": "before-debug-build",
// 调试结束后要执行的任务
"postDebugTask": "after-debug-kill"

添加好后如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb)Launch",
      "type": "cppdbg",
      "request": "launch",
      // 指定带调试符号的可执行程序
      "program": "build/hobot-adas-workflow.gdb",
      "args": [],
      "stopAtEntry": false,
      // 当前工作环境
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      // 指定GDB调试工具
      "miDebuggerPath": "~/SrcCode/toolchain/bin/aarch64-linux-gnu-gdb",
      // 目标远程机器服务地址
      "miDebuggerServerAddress": "remote_ip:port",
      // 开始调试前要执行的任务
      "preLaunchTask": "before-debug-build",
      // 调试结束后要执行的任务
      "postDebugTask": "after-debug-kill"
    }
  ]
}

.vscode目录下新建一个 tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      // 任务名称
      "label": "before-debug-build",
      "type": "shell",
      "command": "bash",
      // 任务要执行的脚本
      "args": ["${workspaceFolder}/start_server.sh"],
      "options": {
        "cwd": "${workspaceFolder}"
      }
    },
    {
      "label": "after-debug-kill",
      "type": "shell",
      "command": "bash",
      "args": ["${workspaceFolder}/kill_server.sh"],
      "options": {
        "cwd": "${workspaceFolder}"
      }
    }
  ]
}

这样每次按F5后,都会自动执行 start_server.sh脚本,调试结束后,会自动执行kill_server.sh脚本。

新建一个 start_server.sh:

# ssh远程执行命令,启动gdbserver
ssh -fn -p port user@remote_ip "cd /mnt/adas-rt/; export LD_LIBRARY_PATH=/mnt/adas-rt/; gdbserver :2333 hobot-adas-workflow"

新建一个kill_server.sh:

# ssh远程执行命令,结束gdbserver
ssh -p 1034 root@10.136.68.101 "killall gdbserver"

这样就能够自动化的用 VSCode 进行远程调试了。