嵌入式 程序调试之gdb和gdbserver的交叉编译及使用
一、简述
记--交叉编译gdb、gdbserver并调试嵌入式程序。
gdb是功能非常强大的常用调试工具,可以直接下断点进行单步调试,是差错排错的利器。
常见三种不同使用场景的gdb:
x86 pc端gdb(以下简称x86-pc-gdb), 是直接运行再x86 PC端的,比如调试 在ubuntu系统的gcc编译出来的程序,在开发pc端程序的时候就是使用该gdb。
交叉编译工具链gdb(pc端)(以下简称arm-pc-gdb):交叉编译工具链编译出来的嵌入式程序就是放在嵌入式设备上运行的程序,交叉编译工具链的gdb是在pc端上调试嵌入式程序产生的coredump文件,以及搭配gdbserver使用的。
交叉编译工具链编译得到的gdb(以下简称arm-gdb):就是能直接在嵌入式设备上运行的gdb。交叉编译工具链编译得到的gdbserver(以下简称arm-gdbserver):就是能直接在嵌入式设备上运行的gdbserver。
相关源码下载:外链:https://wwm.lanzouv.com/b0cb5qtla 密码:bnw
二、使用场景
调试嵌入式程序会使用到交叉编译工具链gdb(以下简称arm-pc-gdb)、交叉编译工具链编译得到的gdb(以下简称arm-gdb)、交叉编译工具链编译得到的gdbserver(以下简称arm-gdbserver)
arm-pc-gdb包含在交叉编译工具链套件中,交叉编译工具链由相关厂家系统提供,或从网上获取。arm-gdb,arm-server需要自己下载gdb源码,使用交叉编译工具链进行编译,编译后会得到arm-gdb, arm-server。arm-gdb一般有几十M,而gdbserver只有几百kb。
使用场景:
1、嵌入式程序崩溃,得到coredump文件,可以直接使用arm-pc-gdb coredump文件进行调试或查看崩溃信息,通常会输入bt指令进行查看栈信息。
2、想要直接调试程序,有的嵌入式程序有相关硬件操作的,所以需要在实际环境上运行才能调试,此时需要arm-gdb,直接将arm-gdb放到嵌入式设备中,然后就跟在pc端使用gdb一样进行调试嵌入式程序。那arm-gdbserver是怎么使用的呢?它是搭配arm-pc-gdb使用的,也就是arm-gdbserver和嵌入式程序在嵌入式设备上运行,嵌入式设备通过网络或其它通道连接到PC机,由PC端的arm-pc-gdb进行实际调试嵌入式程序。可以简单理解为arm-gdbserver就是一个转发作用,为什么要"多次一举"呢?直接使用arm-gdb调试不是更加简单直接吗?原因如下:
a) 通常嵌入式设备是没有源码的,(把源码传输过去?不可取,而且有时候设备是在客户手中),直接使用arm-gdb调试程序时可能只能看到源码文件名和行数,不能直接或不能实时的查看源码,通过arm-gdbserver转发到有源码的的PC端,调试更加方便。
b)通常嵌入式设备的存储空间都是有限的或需要控制成本尽量减少非必须非用户功能的使用, 所以嵌入式设备不会过多移植相关工具,毕竟嵌入式设备是要满足用户需求,而不是搭建完备的调试环境。arm-gdbserver体积比arm-gdb小的多,且在PC端调试,相关的调试工具更加齐全。
c)在pc端可以搭配使用IDE进行可视化,使得调试更加直观方便有效。比如在PC端使用gdb+vscode,可以直接在指定源码行下断点,直接调试,可以实时查看当前内存变量、寄存器,堆栈等信息,是arm-gdb无法比拟的。
三、交叉编译gdb和gdbserver
3.1 下载gdb源码,注:如果需要使用gdbserver, 最好保持跟arm-pc-gdb一样的版本,否则可能会有兼容性问题。
下载连接:http://ftp.gnu.org/gnu/gdb/
3.2 解压并编译
解压源码到当前目录:tar xvf gdb-7.5.tar.gz
得到gdb-7.5目录
创建一个目录用来存放编译得到的gdb,gdbserver:mkdir gdb7.5-arm_build
执行以下指令进行进行配置:
./configure --prefix=/home/liang/gdb-7.5/gdb7.5-arm_build --host=arm-linux CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ LD=arm-linux-gnueabihf-ld AR=arm-linux-gnueabihf-ar
其中--prefix=/home/liang/gdb-7.5/gdb7.5-arm_build指定编译生成的可执行存放路径
执行编译:
make -j8 && make install
编译完成:
将gdb、gdbserver传输到嵌入式设备即可使用,进行调试嵌入式程序。
四、测试使用gdb和gdbserver
4.1 测试代码
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i;
printf("Hello gdb\n");
for (i = 0; i < 5; i++) {
printf("i=%d\n", i);
}
while(i < 10) {
sleep(1);
}
printf("I am exit\n");
return 0;
}
4.2 编译测试代码得到可执行文件test1:arm-linux-gnueabihf-gcc test1.c -o test1 -g
注意需要添加-g选项,添加调试信息。
4.3 将测试程序传输到嵌入式设备进行测试
4.3.1 gdb的使用:
按q退出gdb调试。
4.3.2 gdbserver的使用:注意需要pc端跟嵌入式设备能进行通信,这里使用的是无线网络。
嵌入式设备端:gdbserver先启动, 其中12345是网络通讯端口,自行指定,gdb连接时需要对应上。
pc端(ubuntu):启动arm-linux-gnueabihf-gdb ./test1 (test1需要跟gdbserver启动的程序是同一个)
有源码test1.c才能list出来,否则调试时只有文件名跟行号。
4.3.3 arm-linux-gnueabihf-gdb直接调用coredump文件
测试代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
char *p = NULL;
printf("Hello gdb\n");
*p = 100;
printf("I am exit\n");
return 0;
}
注意:默认系统可能不会产生coredump文件,需要自行设置。
执行:arm-linux-gnueabihf-gdb ./test1 coredump文件