GDB+GDBServer方式进行ARM程序调试
【摘要】:本文首先介绍了gdb+gdbserver相关的概念,然后介绍了其下载、编译、安装等过程;接着介绍了利用gdb+gdbserver调试应用程序的流程及实例等;最后分析了下gdb+gdbserver安装过程中的常见问题。
【关键词】:gdb,gdbserver,远程调试
目录
一、gdb+gdbserver总体介绍...1
二、源代码下载...1
三、配置编译及安装下载...1
四、gdb+gdbservernfs调试流程...2
五、如何利用串口调试...3
六、实战调试...3
远程调试环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接。使用GDB标准程串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能。调试stub是嵌入式系统中的一段代码,作为宿主机GDB和目标机调试程序间的一个媒介而存在。
就目前而言,嵌入式Linux系统中,主要有三种远程调试方法,分别适用于不同场合的调试工作:用ROMMonitor调试目标机程序、用KGDB调试系统内核和用gdbserver调试用户空间程序。这三种调试方法的区别主要在于,目标机远程调试stub的存在形式的不同,而其设计思路和实现方法则是大致相同的。
而我们最常用的是调试应用程序。就是采用gdb+gdbserver的方式进行调试。在很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序。采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采用gdb+gdbserver的方式进行调试。
嵌入式Linux的GDB调试环境由Host和Target两部分组成,Host端使用arm-linux-gdb,TargetBoard端使用gdbserver。这样,应用程序在嵌入式目标系统上运行,而gdb调试在Host端,所以要采用远程调试(remote)的方法。进行GDB调试,目标系统必须包括gdbserver程序(在主机上正对硬件平台编译成功后下载到目标机上),宿主机也必须安装GDB程序。一般Linux发行版中都有一个可以运行的GDB,但开发人员不能直接使用该发行版中的GDB来做远程调试,而要获取GDB的源代码包,针对arm平台作一个简单配置,重新编译得到相应GDB。
我使用的平台是arm cortex a8,gcc-tools的源代码包可以从
http://processors.wiki.ti.com/index.php/Installing_CodeSourcery_Lite
下载完后,进入/opt/目录,配置编译步骤如下:
#tarjxvf gdb-6.5-tar-bz2 #cd gdb-6.5 #./configure--target=arm-linux --prefix=/usr/local/arm-gdb–v (--target配置gdb的目标平台,--prefix配置安装路径,当然其他路径也可以,.跟下面配置一致即可,须在环境变量中声明,启动arm-linux-gdb需要,可更改/etc/profile或~/.bash_profile或~/.bashrc,添加exportPATH=$PATH:/usr/local/arm-gdb/bin,这样可以找到路径) #make |
#makeinstall (生成arm-linux-gdb,并存入/usr/local/arm-gdb/bin/,查询确认下) 也可以启动arm-linux-gdb,若成功,则证明安装无误 进入gdb/gdbserver目录: [root@ddinggdbserver]# pwd /opt/gdb-6.5/gdb/gdbserver [root@ddinggdbserver]#必须在gdbserver目录下运行配置命令,此时才能用相对路径 #./configure--target=arm-linux --host=arm-linux (--target=arm-linux表示目标平台,--host表示主机端运行的是arm-linux-gdb,不需要配置—prefix,因为gdbserver不在主机端安装运行) #makeCC=/usr/local/arm/2.95.3/bin/arm-linux-gcc (这一步要指定你自己的arm-linux-gcc的绝对位置,我试过相对的不行,提示make:arm-linux-gcc:Command notfound,可好多人都用的相对路径,即直接赋值arm-linux-gcc,可采取make时传递参数,也可以直接修改gdbserver目录下的Makefile文件中的环境变量CC) |
没有错误的话就在gdbserver目录下生成gdbserver可执行文件,注意此时要更改其属性,否则可能会出现无法访问的情况,chmod777gdbserver将其更改为任何人都可以读写执行;使用arm-linux-strip命令处理一下gdbserver,将多余的符号信息删除,可让elf文件更精简,通常在应用程序的最后发布时使用;然后把它烧写到flash的根文件系统分区的/usr/bin(在此目录下,系统可以自动找到应用程序,否则必须到gdbserver所在目录下运行之),或通过nfsmount的方式都可以。只要保证gdbserver能在开发板上运行就行。
下面就可以用gdb+gdbserver调试我们开发板上的程序了。在目标板上运行gdbserver,其实就是在宿主机的minicom下。我是在minicom下#mount192.168.2.100:/ /tmp后做的(这里参数-onolock可以不加,不加这一步执行得反而更快些),hello和gdbserver都是位于Linux根目录下,把主机根目录挂在到开发板的/tmp目录下。
要进行gdb调试,首先要在目标系统上启动gdbserver服务。在gdbserver所在目录下输入命令:
(minicom下) #cd/tmp #./gdbserver192.168.2.100:2345 hello |
192.168.2.100为宿主机IP,在目标系统的2345端口(你也可以设其他可用的值,当然必须跟主机的gdb一致)开启了一个调试进程,hello为要调试的程序(必须-g加入调试信息)。
出现提示:
Process/tmp/hello created: pid=80 Listeningon port 2345 (另一个终端Host下) #cd/ #exportPATH=$PATH:/usr/local/arm-gdb/bin #arm-none-linux-gnueabi-gdbhello GNUgdb (Sourcery G++ Lite 2009q1-203) 6.8.50.20081022-cvs Copyright(C) 2008 Free Software Foundation, Inc. LicenseGPLv3+: GNU GPL version 3 or later<http://gnu.org/licenses/gpl.html> Thisis free software: you are free to change and redistribute it. Thereis NO WARRANTY, to the extent permitted by law. Type "showcopying" and"show warranty" for details. ThisGDB was configured as "--host=i686-pc-linux-gnu--target=arm-none-linux-gnueabi". Forbug reporting instructions, please see: <https://support.codesourcery.com/GNUToolchain/>... 最后一行显示:ThisGDBwas configured as“--host=i686-pc-linux-gnu,--target=arm-none-linux-gnueabi”...,如果不一致说明arm-none-linux-gnueabi-gdb有问题 说明此gdb在X86的Host上运行,但是调试目标是ARM代码。 (gdb)target remote 192.168.2.223:2345 (192.168.2.223为开发板IP) |
出现提示:
Remotedebugging using 192.168.2.223:2345 [Newthread 80] [Switchingto thread 80] 0x40002a90in ??() 同时在minicom下提示: Remotedebugging from host 192.168.2.100 (gdb) |
注意:你的端口号必须与gdbserver开启的端口号一致,这样才能进行通信。建立链接后,就可以进行调试了。调试在Host端,跟gdb调试方法相同。注意的是要用“c”来执行命令,不能用“r”。因为程序已经在TargetBoard上面由gdbserver启动了。结果输出是在TargetBoard端,用超级终端查看。连接成功,这时候就可以输入各种GDB命令如list、run、next、step、break等进行程序调试了。
以上针对通过nfsmount和tftp的方式,只能在主机上调试好后下载到开发板上运行,如果有错误要反复这个过程,繁琐不说,有些程序只能在开发板上调试。所以笔者采用了gdbserver的远程调试方式。希望对大家调试程序有用!
如果你用串口1调试hello的话,你就要现在板子上运行命令:
#gdbserverhello /dev/ttyS0(详情可以参考gdbserver目录下的readme文件)
这时gdbserver就在等待gdb的应答信号了。
然后在pc机上运行命令:
#arm-none-linux-gnueabi-gdbhello
在arm-none-linux-gnueabi-gdb里敲入入下命令:
setremotedevice /dev/ttyS0(这里设置串口1)
setremote baud 9600(这里设置串口波特率)
setdebug remote 1(可选)
targetremote /dev/ttyS0
操作到这儿,gdb就应该和gdbserver联系上了。
1.编辑文件
#vi gdbtest.c
1#include <stdio.h>
2
3int
4func(int n){
5 int sum=0, i;
6 for (i=0; i<n; i++){
7 sum += i;
8 }
9 return sum;
10}
11
12int
13main(void)
14{
15 int i;
16 long result = 0;
17 for (i=0; i<=100; i++){
18 result += i;
19 }
20
21 printf("result[1-100] = %d \n", result);
22 printf("resutl[1-225] = %d \n", func(255));
23
24 return 0;
25}
#arm-none-linux-gnueabi-gcc-ggdbtest.c -o gdbtest // 交叉编译
2.下载文件到目标板:gdbtest和gdbserver
假设hostpc ip:192.168.1.45
board ip:192.168.1.180
将文件拷贝到目标板上:
先将gdbtest和gdbserver两个文件拷贝到主机的/tftpboot目录下,此时系统主机和目标机都必须能够支持nfs
在目标板的Linux中运行:
#mount192.168.1.108:/tftpboot /mnt/nfs
#cd/mnt/nfs
#ls
看是否有gdbtest和gdbserver两个文件。
3.运行调试
clientboard:
#./gdbserver192.168.1.45:1234 gdbtest //目标板上运行gdbtest监听端口1234
[root@AT91RM9200DKarm]$./gdbserver192.168.0.12:2345 mainparacarm
./gdbserver:error in loading shared libraries: libthread_db.so.1: cannot open[root@AT91RM9200DKarm]$
hostpc:
#arm-none-linux-gnueabi-gdbgdbtest
(gdb)targetremote 192.168.1.180:1234 //连接到开发板成功后就可以
进行调试
(gdb)list or l
(gdb)breakfunc
(gdb)break22
(gdb)infobr
(gdb)continue or c //这里不能用run
(gdb)next or n
(gdb)printor p result
(gdb)finish //跳出func函数
(gdb)next
(gdb)quit
建立连接后进行gdb远程调试和gdb本地调试方法相同