LV001-gdb简介
Tips:本节涉及到的arm开发板相关内容都是野火Lubancat2相关的。
一、调试器
1. 什么是调试器?
程序中的错误主要分为两类,分别为语法错误和逻辑错误:程序中的语法错误几乎都可以由编译器诊断出来,很容易就能发现并解决;逻辑错误指的是代码思路或者设计上的缺陷,程序出现逻辑错误的症状是:代码能够编译通过,没有语法错误,但是运行结果不对,反复检查了很多遍,依然不知道哪里出了问题。这个时候,就需要调试程序了。
所谓 调试(Debug),就是让代码一步一步慢慢执行,跟踪程序的运行过程。比如,可以让程序停在某个地方,查看当前所有变量的值,或者内存中的数据;也可以让程序一次只执行一条或者几条语句,看看程序到底执行了哪些代码。
程序中出现的 语法错误可以借助编译器解决;但 逻辑错误(是指代码思路或者设计上的缺陷)则只能靠自己解决,而解决逻辑错误最高效的方法,就是 借助调试工具对程序进行调试。
在调试的过程中,我们可以监控程序的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。
编译程序需要借助专业的编译器,调试程序也需要借助专业的辅助工具,即调试器。
2. 常见调试器
常见的一些调试器如下:
| Remote Debugger | Remote Debugger 是 VC/VS 自带的调试器,与整个 IDE 无缝衔接,使用非常方便。 |
| WinDbg | 大名鼎鼎的 Windows 下的调试器,它的功能甚至超越了 Remote Debugger,它还有一个命令行版本(cdb.exe),但是这个命令行版本的调试器指令比较复杂。 |
| LLDB | XCode 自带的调试器,Mac OS X 下开发必备调试器。 |
| GDB | Linux 下使用最多的一款调试器,也有 Windows 的移植版。 |
1. 什么是 GDB
GDB 全称 GNU symbolic debugger ,诞生于 GNU 计划(同时诞生的还有 GCC 、 Emacs 等),是 Linux 下常用的程序调试器。当下的 GDB 支持调试多种编程语言编写的程序,包括 C 、 C++ 、 Go 、 Objective-C 、 OpenCL 、 Ada 等。官网在:GDB: The GNU Project Debugger
我们可以通过 GDB 调试器实现以下几个功能:
- 程序启动时,可以按照我们自定义的要求运行程序,例如设置参数和环境变量;
- 可使被调试程序在指定代码处暂停运行,并查看当前程序的运行状态(例如当前变量的值,函数的执行结果等),即支持断点调试;
- 程序执行过程中,可以改变某个变量的值,还可以改变代码的执行顺序,从而尝试修改程序中出现的逻辑错误。
2. pc-gdb 和 arm-gdb
为方便描述,后续称运行在 ubuntu 中,调试宿主机 gcc 编译出来的 c 程序(运行在宿主机上的) gdb 为 pc-gdb。运行在 arm 开发板上,调试通过宿主机交叉编译出来的 c 程序(c 程序运行在 arm 开发板)的 gdb 为 arm-gdb。
3. 下载和安装
这里看官网就可以了:Download GDB。一般来说,我们安装 gcc 的时候,附带会一起安装 gdb,例如我在 ubuntu20.04 中:
✓ sumu@virtual-machine:~/workspace/c-learning [main ≡]$ gdb -v
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
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.其实我们一般做开发都是在编译服务器进行交叉编译,这个时候我们会安装交叉编译工具链,一般交叉工具编译链中都会附带 gdb 工具:

但是这个是在 PC(x86 架构)上使用的,并不能在开发板使用,我们可以试一下:
这个时候想要在开发板使用 gdb,就需要从源码交叉编译 gdb(四、源码编译 arm-gdb/gdbserver),然后复制到开发板去。当然,要是开发板能联网的话,也可以直接 apt 安装 gdb。
sudo apt-get update
sudo apt-get install -y gdb三、gdbserver
Tips:Server (Debugging with GDB)、gdbserver(1) - Linux manual page
1. 什么是 gdbserver
gdbserver 是一个程序,它允许宿主机可以通过网络,远程调试目标板。也就是允许我们在与运行被调试程序的机器不同的机器上运行 GDB。即 gdb 和被调试程序分别在两个机器上运行。我们使用 man gdbserver 命令就可以看到对于 gdbserver 的一些说明。
要使用服务器,我们需要登录到目标系统,然后运行 gdbserver 程序。 我们必须告诉它: (a) 如何与 GDB 通信,(b) 程序的名称,以及 (c) 它的参数。 一般语法是:
target> gdbserver <comm> <program> [<args> ...]例如,使用串行端口,我们可能会执行:
target> gdbserver /dev/com1 emacs foo.txt这告诉 gdbserver 使用 foo.txt 的参数调试 emacs,并通过 /dev/com1 与 GDB 通信。 gdbserver 现在耐心等待主机 GDB 与其通信。
要使用 TCP 连接,我们可以:
target> gdbserver host:2345 emacs foo.txt这与上一个示例几乎相同,除了我们将通过 TCP 与“主机”GDB 通信。 “host: 2345”参数意味着我们希望看到从“host”到本地 TCP 端口 2345 的 TCP 连接。(目前,“host”部分被忽略)我们可以为端口号选择任何数字 只要它不与目标系统上的任何现有 TCP 端口冲突。 在主机 GDB 的“target remote”命令中必须使用相同的端口号,稍后将对此进行描述。 请注意,如果我们选择的端口号与其他服务冲突,gdbserver 将打印错误消息并退出。
gdbserver 还可以 attach 到正在运行的程序。 这是通过 --attach 参数完成的。 语法是:
target> gdbserver --attach <comm> <pid>pid 是当前正在运行的进程的进程 ID。 没有必要将 gdbserver 指向正在运行的进程的二进制文件。
还有一些详细的内容可以看对应的 man 手册。
2. 为什么要用?
为什么要交叉编译?主要原因还不是大部分 arm 芯片的性能不足,无法支持编译大型程序,那么 gdbserver 也一样。由于大部分我们使用的嵌入式 arm 芯片性能都不是很强,无法安装或者根本跑不动完整的 gdb,这个时候就 gdbserver 就可以上场了。当然,也不是没有性能强大的嵌入式芯片,性能够呛就可以直接运行 gdb。
嵌入式系统中一般在 PC 端运行 gdb 工具,源码也是在 PC 端,源码对应的可执行文件放到开发板中运行。为此我们需要在开发板中运行 gdbserver,通过网络与 PC 端的 gdb 进行通信。gdbserver 体积极小(几百 KB),本身不解析符号表,不依赖源码,只在目标端完成最基本的进程控制与数据传输。
3. 下载和安装
一般来说,我们安装的交叉编译工具链中会提供对应的 gdb 工具:

这个其实就是搭配 gdbserver 来使用的。然后我们还需要 gdbserver,这个我们可以直接从源码编译安装(有的 SDK 提供的交叉编译工具链可能会直接提供,这样的话就直接拷贝到开发板使用即可)。可以参考 四、源码编译 arm-gdb/gdbserver。
要是开发板能联网的话,也可以直接 apt 安装 gdb。
sudo apt-get update
sudo apt-get install -y gdbserver4. arm-pc-gdb
我们需要在宿主机运行 gdb,上面有说明这个宿主机(我这里是 ubuntu20.04)运行的 gdb 一般交叉编译工具会提供,我们可以看一下版本。我使用的是野火 lubancat2 的 sdk,使用的交叉编译工具是:LubanCat/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu,运行可能会有下面的一些报错:
# ./aarch64-none-linux-gnu-gdb: error while loading shared libraries: libncursesw.so.5: cannot open shared object file: No such file or directory
sudo apt update && sudo apt install libncursesw5
#./aarch64-none-linux-gnu-gdb: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory
sudo apt install -y libpython2.7然后后面就可以直接查看版本了:
✓ sumu@virtual-machine:~/workspace/cnb-lubancat/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin [adbb295] $ ./aarch64-none-linux-gnu-gdb -v
GNU gdb (GNU Toolchain for the A-profile Architecture 10.3-2021.07 (arm-10.29)) 10.2.90.20210621-git
Copyright (C) 2021 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.四、源码编译 arm-gdb/gdbserver
1. 下载源码
我们来这里下载:Index of /gnu/gdb,这里有很多版本,我们选一个和交叉编译工具差不多的版本,交叉编译工具中是:
GNU gdb (GNU Toolchain for the A-profile Architecture 10.3-2021.07 (arm-10.29)) 10.2.90.20210621-git
Copyright (C) 2021 Free Software Foundation, Inc.会发现没有这个 10.3 的版本:

有可能是交叉编译工具链选的更早的版本,然后重新编译的,这里我们选一个相近的 gdb-10.2.tar.gz,下载后解压即可。

2. arm-gdb/gdbserver
这里会同时编译出 arm-gdb 和 gdbserver 我们执行下面的命令进行交叉编译和安装:
cd ~/workspace/cnb-lubancat/gdb-10.2
mkdir build # 在 gdb 源码下新建 build 目录, gdb 编译比较奇葩!不能直接在 gdb 源码目录下进行配置和编译,必须新建一个文件夹,然后在此文件夹下配置和编译,切记!
mkdir -p build/_install
cd build # 进入到刚刚创建的 build 目录下
export PATH=$PATH:/home/sumu/workspace/cnb-lubancat/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
# 配置完成以后会在 build 目录下生成 Makefile 文件。
# --target: 目标机交叉编译器前缀,也就是使用的交叉编译器前缀, GDB 调试的目标架构
# --host : 指定编译后的程序在哪里运行,需要在 PC(本地) 上运行的话可以不设置,编译 gdbserver 的时候就要设置为 arm-linux(要和目标交叉编译器前缀相同,rk 的话就是 aarch64-none-linux-gnu)。
# --prefix: 指定安装目录。
../configure --prefix=/home/sumu/workspace/cnb-lubancat/gdb-10.2/build/_install \
--host=aarch64-none-linux-gnu \
--program-prefix=arm-aarch64-none-linux-gnu- \
--target=aarch64-none-linux-gnu \
--disable-werror
make -j8 && make install中间没有出现报错的话一般问题不大,我这里没遇到报错,后续有坑再补充。然后会在_install/bin 目录下看到这些文件:
✓ sumu@virtual-machine:~/workspace/cnb-lubancat/gdb-10.2/build/_install/bin
$ ls -alh
总用量 122M
drwxrwxr-x 2 sumu sumu 4.0K 5月 3 11:45 .
drwxrwxr-x 6 sumu sumu 4.0K 5月 3 11:45 ..
-rwxr-xr-x 1 sumu sumu 3.6K 5月 3 11:45 arm-aarch64-none-linux-gnu-gcore
-rwxr-xr-x 1 sumu sumu 104M 5月 3 11:45 arm-aarch64-none-linux-gnu-gdb
-rwxr-xr-x 1 sumu sumu 4.0K 5月 3 11:45 arm-aarch64-none-linux-gnu-gdb-add-index
-rwxr-xr-x 1 sumu sumu 6.3M 5月 3 11:45 arm-aarch64-none-linux-gnu-gdbserver
-rwxr-xr-x 1 sumu sumu 12M 5月 3 11:45 arm-aarch64-none-linux-gnu-run我们可以看一下这个文件的格式,它是运行在 ARM aarch64 平台的:
✗ sumu@virtual-machine:~/workspace/cnb-lubancat/gdb-10.2/build/_install/bin
$ file arm-aarch64-none-linux-gnu-gdb
arm-aarch64-none-linux-gnu-gdb: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, with debug_info, not stripped
$ file arm-aarch64-none-linux-gnu-gdbserver
arm-aarch64-none-linux-gnu-gdbserver: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, with debug_info, not stripped我们可以拷贝到开发板(编译出来的是运行在 arm 开发板上的 本地 gdb 和 gdbserver):
sudo cp arm-aarch64-none-linux-gnu-gdb arm-aarch64-none-linux-gnu-gdbserver ~/4nfs/c-leaning/查看一下这个版本:
root@lubancat:~/nfs_temp/c-leaning# ./arm-aarch64-none-linux-gnu-gdb --version
GNU gdb (GDB) 10.2
Copyright (C) 2021 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.
root@lubancat:~/nfs_temp/c-leaning# ./arm-aarch64-none-linux-gnu-gdbserver --version
GNU gdbserver (GDB) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
gdbserver is free software, covered by the GNU General Public License.
This gdbserver was configured as "aarch64-none-linux-gnu"3. arm-pc-gdb
如果之前编译过 arm-gdb,这里需要删除 build 目录下所有文件。
mkdir build-pc # 在 gdb 源码下新建 build 目录, gdb 编译比较奇葩!不能直接在 gdb 源码目录下进行配置和编译,必须新建一个文件夹,然后在此文件夹下配置和编译,切记!
mkdir -p build-pc/_install
cd build-pc # 进入到刚刚创建的 build 目录下
export PATH=$PATH:/home/sumu/workspace/cnb-lubancat/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
# 配置完成以后会在 build 目录下生成 Makefile 文件。
# --target: 目标机交叉编译器前缀,也就是使用的交叉编译器前缀, GDB 调试的目标架构
# --host : 指定编译后的程序在哪里运行,需要在 PC(本地) 上运行的话可以不设置,编译 gdbserver 的时候就要设置为 arm-linux(要和目标交叉编译器前缀相同,rk 的话就是 aarch64-none-linux-gnu)。
# --prefix: 指定安装目录。
../configure \
--prefix=/home/sumu/workspace/cnb-lubancat/gdb-10.2/build-pc/_install \
--program-prefix=arm-pc-aarch64-none-linux-gnu- \
--target=aarch64-none-linux-gnu \
--disable-werror
make -j8 && make install这个编译出来的是 arm-pc-gdb,是运行在 ubuntu,搭配开发板中的 gdbserver 进行调试的 gdb,我们可以看一下文件格式:
✓ sumu@virtual-machine:~/workspace/cnb-lubancat/gdb-10.2/build-pc/_install/bin
$ file arm-pc-aarch64-none-linux-gnu-gdb
arm-pc-aarch64-none-linux-gnu-gdb: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8e63068e914842a75f6e1ec97d336d82600db1f5, for GNU/Linux 3.2.0, with debug_info, not stripped4. gdbserver
我们也可以单独编译gdbserver。但是呢,并不推荐,我试了一下,一会报缺这个库,一会报缺那个头文件的,坑多,还是整体编译吧。
参考资料:
gdbserver 指南 - JiMoKuangXiangQu - 博客园
(13 封私信) gdb 与 gdbserver 的安装与使用 - 知乎