嵌入式GDB调试搭建与使用
文件夹下,比如笔者的就是/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin。gcc-linaro-4.9.4- 2017.01-x86_64_arm-linux-gnueabihf/bin,如图。目标机交叉编译器前缀,也就是你所使用的交叉编译器前缀,比如在本教程中就设置为 arm-linux-gnueabih
在学习单片机的时候我们可以通过集成式 IDE 来进行调试,比如 MDK、IAR 等。在嵌入式 linux 领域是否也可以进行调试呢?答案肯定是可以的,在嵌入式 linux 领域我们最常用的就是 GDB 调试工具,通过 GDB 来调试嵌入式 C 程序。本章我们首先学习如何搭建嵌入式 Linux的 GDB 调试环境,然后讲解如何使用 GDB 工具调试 C 程序。
GDB 简介
gdb 工具是 GNU 项目调试器,基于命令行。和其他的调试器一样,我们可以使用 gdb 来一行行的运行程序、单步执行、跳入/跳出函数、设置断点、查看变量等等,它是 UNIX/LINUX 操作系统下强大的程序调试工具。gdb 支持多种语言,包括 Ada、汇编、C/C++、D、Fortran、GO、Objective-C、OpenCL、Modula-2、Pascal 和 Rust。关于 gdb 更多详细的信息请到 gdb 官网查阅,gdb 官网地址为:www.gnu.org。
一般的桌面 Linux 系统,比如 ubuntu、centos 等,我们可以直接运行 gdb 来调试程序。但是嵌入式中芯片性能一般比较弱,所以直接在嵌入式系统中运行 gdb 不太现实(性能强大的嵌入式芯片可以这么做)。嵌入式系统中一般在 PC 端运行 gdb 工具,源码也是在 PC 端,源码对应的可执行文件放到开发板中运行。为此我们需要在开发板中运行 gdbserver,通过网络与 PC 端的 gdb 进行通信。因此要想在 PC 上通过 gdb 调试嵌入式程序,那么需要两个东西:gdb 和gdbserver,其中 gdb 是运行在 PC 上的,gdbserver 需要我们移植到开发板上。
GDB 移植
一般交叉编译已经自带了 gdb 和 gdbserver,因此可以不用移植,直接使用交叉编译器自带的即可。比如本教程所使用的 arm-linux-gnueabihf-gcc 就自带了主机使用的 arm-linux-gnueabihf-gdb 和开发板所使用的 gdbserver。进入 ubuntu 中交叉编译器安装目录中的 bin 文件夹下,比如笔者的就是/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin,此目录中就包含了 arm-linux-gnueabihf-gdb 和 gdbserver,如图 B3.2.1 所示:
如果交叉编译器自带了 gdb 和 gdbserver 的话只需要将 gdbserver 拷贝到开发板根文件系统的/bin 目录下。
如果交叉编译器没有自带 gdb 和 gdbserver 那就需要自己手动编译了。
获取 gdb 和 gdbserver 源码
首先到 gdb 官网上获取源码,地址为 http://www.gnu.org/software/gdb/download/,在笔者写本教程的时候,最新的 gdb 源码版本为 9.1。已经放到了开发板光盘中,路径为:1、例程源码 ->7、第三方库源码-> gdb-9.1.tar.gz。将 gdb 源码发送到 ubuntu 中中并解压,命令如下:
tar -vxzf gdb-9.1.tar.gz
解压完成以后就会得到一个名为 gdb-9.1 的文件夹,此文件夹就是 gdb 和 gdbserver 源码,其中 gdb-9.1/gdb/gdbserver 目录就是 gdbserver 源码。
编译 gdb
1、编译 gdb
首先编译 gdb,gdb 是运行在 PC 端的程序,gdb 编译的时候需要进行配置,配置项如下:
--target:目标机交叉编译器前缀,也就是你所使用的交叉编译器前缀,比如在本教程中就设置为 arm-linux-gnueabihf。
--host:指定编译后的程序在哪里运行,编译 gdb 的时候就需用设置,因为我们是需要在 PC上运行的,编译 gdbserver 的时候就要设置为 arm-linux。
--prefix:指定安装目录。
创建一个名为“gdb”的文件夹,用来保存编译后的 gdb 和 gdbserver,路径自行选择。gdb编译比较奇葩!使用如下命令配置并编译 gdb:
cd gdb-9.1/ //进入 gdb 源码目录
mkdir build //在 gdb 源码下新建 build 目录,gdb 编译比较奇葩!不能直接在 gdb 源
//码目录下进行配置和编译,必须新建一个文件夹,然后在此文件夹下配
//置和编译,切记!
cd build //进入到刚刚创建的 build 目录下
../configure --target=arm-linux-gnueabihf --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/gdb
//配置 gdb。配置完成以后会在 build 目录下生成 Makefile 文件。
make //编译
make install //安装
编译完成以后PC端运行的gdb工具就会安装到gdb/bin目录下,名字为arm-linux-gnueabihf-gdb,如图 B3.2.2.1 所示:
图 B3.2.2.1 中的 arm-linux-gnueabihf-gdb 就会我们编译得到的 gdb 工具,输入如下命令运行此 gdb:
cd gdb/bin //进入到 bin 目录下
./arm-linux-gnueabihf-gdb //运行此 gdb
结果如图 B2.2.2.2 所示:
从图 B3.2.2.2 可以看出,arm-linux-gnueabihf-gdb 版本号为 9.1,说明编译安装成功,输入“q”可以退出 gdb 工具。
2、关闭交叉编译器自带的 gdb
我们安装的 arm-linux-gnueabihf 交叉编译器已经默认自带了一个名为“arm-linux-gnueabihf-gdb”的 gdb 工具!大家可以到自己的交叉编译器安装目录看一下,相对路径为:gcc-linaro-4.9.4- 2017.01-x86_64_arm-linux-gnueabihf/bin,如图 B3.2.2.3 所示:
从图 B3.2.2.3 可以看出,编译器自带的 gdb 工具和我们编译出来的 gdb 名字一样,这两个都可以使用,也就是说我们可以不用自行编译 gdb,直接使用交叉编译器里面的也是可以的!
只是这两个 gdb 的版本号可能不一样,可以查看一下交叉编译器自带的 gdb 工具版本号,我这里如图 B3.2.2.4 所示:
从图 B3.2.2.4 可以看出,交叉编译器自带的 gdb 工具版本号为 7.10。现在有个问题,一山不能容二虎, 9.1 版本和 7.10 版本只能留一个,我测试过,这两个任意哪一个都可以。这里我们使用自己编译的 9.1 版本的 gdb 工具,因此需要对交叉编译器自带的 7.10 版本的 gdb 工具重命名,这里笔者将其重命名为“arm-linux-gdb”。
最后打开 ubuntu 的/etc/profile 文件,修改 PATH 环境变量值,将我们编译出来的 9.1 版本的“arm-linux-gnueabihf-gdb”所在的路径添加进去,这样我们就可以直接使用此 gdb 了,根据自己的实际情况修改 PATH 值,比如我的 PATH 内容如下:
export PATH=/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin:/home/zuozhongkai/linux/IMX6ULL/tool/gdb/bin:$PATH
其中红色加粗部分就是我所编译出来的 9.1 版本 gdb 工具所存放的路径,修改完以后重启
ubuntu,这个时候我们就可以使用命令“arm-linux-gnueabihf-gdb”来打开 gdb 调试器了。
移植 gdbserver
接下来移植 gdbserver,gdbserver 是在开发板上运行的,因此要交叉编译。gdbserver 源码保存在 gdb-9.1/gdb/gdbserver 目录下,进入此目录,然后输入如下命令配置并编译:
cd gdb-9.1/gdb/gdbserver //进入到 gdbserver 目录
./configure --target=arm-linux-gnueabihf --host=arm-linux-gnueabihf //配置
make CC=arm-linux-gnueabihf-gcc //交叉编译 gdbserver
编译完成以后就会在目录下生成一个名为“gdbserver”的文件,这个就是我们需要放到开发板上去的 gdbserver,如图 B3.2.3.1 所示:
将图 B3.2.3.1 中交叉编译出来的 gdbserver 软件发送到开发板中的/usr/bin 目录下,完成以后在开发板中输入如下命令查看 gdbserver 版本号:
gdbserver –version //查看版本号
如果 gdbserver 移植成功的话就会打印出其版本号,如图 B3.2.3.2 所示:
从图 B3.2.3.2 可以看出,当前 gdbserver 版本号为 9.1,说明我们的移植是成功的。PC 上的gdb 和开发板上的 gdbserver 都已经准备好了,接下来就是使用这两个工具来完成调试。
使用 GDB 进行嵌入式程序调试
编写一个测试应用
首先编写一个简单的测试软件,我们一会就用 gdb 来调试这个软件,新建名为 gdbtest.c 的文件,在里面输入如下所示内容:
使用 arm-linux-gnueabihf-gcc 交叉编译 gdbtest.c 文件,要想调试程序,那么编译的时候必须加上“-g”选项,这样编译出来的可执行文件才带有调试信息,这一点一定要切记!编译命令如下所示:
arm-linux-gnueabihf-gcc gdbtest.c -o gdbtest -g //编译测试程序,注意-g 选项
编译完成以后将得到的 gdbtest 可执行文件发送到开发板中。
GDB 调试程序
一切准备就绪以后就可以使用GDB进行调试了,确保ubuntu和开发板可以进行网络通信。
在开发板中输入如下命令:
gdbserver 192.168.1.253:2001 gdbtest //启动开发板上的 gdbserver
上述命令中 192.168.1.253 为调试机的 IP 地址,也就是 ubuntu 的 IP 地址,2001 是端口号,可以任意给一个端口号,gdbtest 是要调试的可执行文件。输入以后开发板输出信息如图 B3.3.2.1所示:
接着在 ubuntu 中输入如下命令启动 gdb 调试工具:
arm-linux-gdb gdbtest
结果如图 B3.3.2.2 所示:
图 B3.3.2.2 中最下面的(gdb)行用于输入命令,输入如下命令连接到开发板上:
target remote 192.168.1.251:2001 //连接到开发板上
上述命令表示连接到开发板上,其中 192.168.1.251 就是开发板 IP 地址,2001 就是开发板gdbserver 设置的端口号。连接成功以后开发板中的 gdbserver 就会提示连接信息,如图 B2.3.2.3 所示:
从图 B3.3.2.3 可以看出,远端调试机的 IP 地址为 192.168.1.253,也就是我们的 ubuntu 址连接成功以后就可以在 ubuntu 上进行代码调试了。gdb 工具是一个基于命令行的调试工具,我们就来学习一下常用的几个命令。
1、l 命令
l 命令(list)用于列出所有程序源码,输入“l”,结果如图 B3.3.2.4 所示:
从图 B3.3.2.4 可以看出,输入“l”命令以后就打印出了调试程序的所有源码,如果源码没有打印完的话就重复按下“l”命令,或者按下回车键,gdb 调试工具中回车键表示重复上一个命令!
2、b 命令
b 命令(break)用于设置断点,也可以用缩写“b”,后面可以跟具体的函数或者行号,比如“break main”表示在 main 函数处设置断点,“break 11”在第 11 行设置断点。输入如下命令,在 main 函数处设置断点:
b main 或 break main
设置以后提示如图 B3.3.2.5 所示:
从图 B3.3.2.5 可以看出,断点 1 设置到了 gdbtest.c 的第 6 行,大家可以看一下图 B3.3.2.4,第 6 行正好是 main 函数的起始处。
3、c 命令
c 命令用于运行到断点处,输入 c 命令程序就会运行,直到下一个断点处,如图 B3.3.2.6 所示:
从图 B3.3.2.6 可以看出,当前程序运行到第 6 行停止,因为我们前面在第 6 行放置了一个断点,因此程序运行停止。继续输入“c”命令,程序就会持续不断的运行,开发板中就会不断的打印出信息,如图 B3.3.2.7 所示:
4、s 命令
s 命令(step)是单步运行执行,此函数会进入到函数里面。
5、n 命令
n 命令(next)也是单步运行,但是 n 命令不会进入到函数里面。
6、p 命令
p 命令(print)用于打印某个变量值。
7、q 命令
q 命令(quit)用于退出调试,开发板上的 gdbserver 也会停止。
关于 gdb 调试更多详细的使用方法和命令大家自行上网查阅,这里就不一一介绍了。
更多推荐
所有评论(0)