1
Gdb+gdbserver 方式进行 ARM 程序调试
(Version 1.01)
【摘要】:本文首先介绍了 gdb+gdbserver相关的概念,然后介绍了其下载、编译、安装等过程;接着介绍了
利用 gdb+gdbserver调试应用程序的
流程
快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计
及实例等;最后分析了下 gdb+gdbserver安装过程中的常见问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
。
【关键词】:gdb,gdbserver,远程调试
目录
目录 ............................................................................................................................................................................... 1
1.gdb+gdbserver 总体介绍 .......................................................................................................................................... 1
2.源代码下载................................................................................................................................................................ 1
3.配置编译及安装下载(以 gdb-6.5 为例) .................................................................................................................. 2
4.gdb+gdbservernfs 调试流程 ..................................................................................................................................... 3
5.如何利用串口调试 ................................................................................................................................................... 5
6.实战调试 .................................................................................................................................................................... 6
7.附件 ............................................................................................................................................................................ 9
1. gdb+gdbserver 总体介绍
远程调试环境由宿主机 GDB 和目标机调试 stub 共同构成,两者通过串口或 TCP 连接。使用 GDB
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
程
串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能。调试 stub 是嵌入式系统中的一
段代码,作为宿主机GDB和目标机调试程序间的一个媒介而存在。就目前而言,嵌入式 Linux系统中,主要有
三种远程调试方法,分别适用于不同场合的调试工作:用 ROMMonitor 调试目标机程序、用 KGDB 调试系统内
核和用 gdbserver 调试用户空间程序。这三种调试方法的区别主要在于,目标机远程调试 stub 的存在形式的不
同,而其
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
思路和实现方法则是大致相同的。而我们最常用的是调试应用程序。就是采用 gdb+gdbserver 的
方式进行调试。在很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序。采用 GDB 方法
调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采用 gdb+gdbserver 的方式进
行调试。
2. 源代码下载
2
嵌入式 Linux 的 GDB 调试环境由 Host 和 Target 两部分组成,Host 端使用 arm-linux-gdb,Target Board 端使
用 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
下载完成后双击安装就可以了,但是编译的交叉工具链需要自己编译安装。
3. 配置编译及安装下载(以 gdb-6.5 为例)
下载完后,进入/opt/目录,配置编译步骤如下:
#tar jxvf 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
#make install
(生成 arm-linux-gdb,并存入/usr/local/arm-gdb/bin/,查询确认下)
也可以启动 arm-linux-gdb,若成功,则证明安装无误
进入 gdb/gdbserver 目录:
3
[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 不在主机端安装运行)
#make CC=/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 能在开发板上运行就行。
4. gdb+gdbservernfs 调试流程
下面就可以用 gdb+gdbserver 调试我们开发板上的程序了。在目标板上运行 gdbserver,其实就是在宿主机
的 minicom 下。我是在 minicom 下#mount 192.168.2.100:/ /tmp 后做的(这里参数-onolock 可以不加,不加这一步
执行得反而更快些),hello 和 gdbserver 都是位于 Linux 根目录下,把主机根目录挂在到开发板的/tmp 目录下。
要进行 gdb 调试,首先要在目标系统上启动 gdbserver 服务。在 gdbserver 所在目录下输入命令:
(minicom 下)
#cd/tmp
4
#./gdbserver192.168.2.100:2345 hello
192.168.2.100 为宿主机 IP,在目标系统的 2345 端口(你也可以设其他可用的值,当然必须跟主机的 gdb 一致)
开启了一个调试进程,hello 为要调试的程序(必须-g 加入调试信息)。
出现提示:
Process /tmp/hello created: pid=80
Listening on port 2345
(另一个终端 Host 下)
#cd/
#exportPATH=$PATH:/usr/local/arm-gdb/bin
#arm-none-linux -gnueabi-gdb hello
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
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.
This GDB was configured as "--host=i686-pc-linux -gnu--target=arm-none-linux -gnueabi".
Forbug reporting instructions, please see:
...
5
最后一行显示:This GDBwas 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 下提示:
Remote debugging from host 192.168.2.100
(gdb)
注意:你的端口号必须与 gdbserver 开启的端口号一致,这样才能进行通信。建立链接后,就可以进行调试
了。调试在 Host 端,跟 gdb 调试方法相同。注意的是要用―c‖来执行命令,不能用―r‖。因为程序已经在
TargetBoard 上面由 gdbserver 启动了。结果输出是在 TargetBoard 端,用超级终端查看。连接成功,这时候就可
以输入各种 GDB 命令如 list、run、next、step、break 等进行程序调试了。
以上针对通过 nfs mount和 tftp的方式,只能在主机上调试好后下载到开发板上运行,如果有错误要反复这
个过程,繁琐不说,有些程序只能在开发板上调试。所以笔者采用了 gdbserver 的远程调试方式。希望对大家
调试程序有用!
5. 如何利用串口调试
6
如果你用串口 1 调试 hello 的话,你就要现在板子上运行命令:
#gdbserver hello /dev/ttyS0(详情可以参考 gdbserver 目录下的 readme 文件)
这时 gdbserver 就在等待 gdb 的应答信号了。
然后在 pc 机上运行命令:
#arm-none-linux -gnueabi-gdb hello
在 arm-none-linux -gnueabi-gdb 里敲入入下命令:
set remote device /dev/ttyS0(这里设置串口 1)
set remote baud 9600(这里设置串口波特率)
set debug remote 1(可选)
target remote /dev/ttyS0
操作到这儿,gdb 就应该和 gdbserver 联系上了。
6. 实战调试
1.编辑文件
# vi gdbtest.c
1#include
2
3int
4func(int n){
5 int sum=0, i;
7
6 for (i=0; i)和外壳通配符(*、?、[、])在内。
如果你使用不带参数的 run 命令,gdb 就再次使用你给予前一条 run 命令的参数,这是很有用的。利
用 set args 命令就可以修改发送给程序的参数,而使用 show args 命令就可以查看其缺省参数的列
表。
(gdb) set args –b –x
(gdb) show args
backtrace 命令为堆栈提供向后跟踪功能。
Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。
三:显示数据
利用 print 命令可以检查各个变量的值。
(gdb) print p (p 为变量名)
whatis 命令可以显示某个变量的类型
(gdb) whatis p
type = int *
print 是 gdb 的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了
包含你程序中的变量外,还可以包含以下内容:
l 对程序中函数的调用
(gdb) print find_entry(1,0)
11
l 数据结构和其他复杂对象
(gdb) print *table_start
$8={e=reference=’/000’,location=0x0,next=0x0}
l 值的历史成分
(gdb)print $1 ($1 为历史
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
变量,在以后可以直接引用 $1 的值)
l 人为数组
人为数组提供了一种去显示存储器块(数组节或动态分配的存储区)内容的方法。早期的调试程序没有
很好的方法将任意的指针换成一个数组。就像对待参数一样,让我们查看内存中在变量 h 后面的 10 个整
数,一个动态数组的语法如下所示:
base@length
因此,要想显示在 h 后面的 10 个元素,可以使用 h@10:
(gdb)print h@10
$13=(-1,345,23,-234,0,0,0,98,345,10)
四:断点(breakpoint)
break 命令(可以简写为 b)可以用来在调试的程序中设置断点,该命令有如下四种形式:
l break line-number 使程序恰好在执行给定行之前停止。
l break function-name 使程序恰好在进入指定的函数之前停止。
l break line-or-function if condition 如果 condition(条件)是真,程序到达指定行或函数时停止。
l break routine-name 在指定例程的入口处设置断点
如果该程序是由很多原文件构成的,你可以在各个原文件中设置断点,而不是在当前的原文件中设置断
点,其方法如下:
(gdb) break filename:line-number
(gdb) break filename:function-name
要想设置一个条件断点,可以利用 break if 命令,如下所示:
(gdb) break line-or-function if expr
例:
(gdb) break 46 if testsize==100
1
2
从断点继续运行:countinue 命令
五.断点的管理
1. 显示当前 gdb 的断点信息:
(gdb) info break
他会以如下的形式显示所有的断点信息:
Num Type Disp Enb Address What
1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155
2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168
(gdb)
2.删除指定的某个断点:
(gdb) delete breakpoint 1
该命令将会删除编号为 1 的断点,如果不带编号参数,将删除所有的断点
(gdb) delete breakpoint
3.禁止使用某个断点
(gdb) disable breakpoint 1
该命令将禁止断点 1,同时断点信息的 (Enb)域将变为 n
4.允许使用某个断点
(gdb) enable breakpoint 1
该命令将允许断点 1,同时断点信息的 (Enb)域将变为 y
5.清除原文件中某一代码行上的所有断点
(gdb)clean number
注:number 为原文件的某个代码行的行号
六.变量的检查和赋值
whatis:识别数组或变量的类型
ptype:比 whatis 的功能更强,他可以提供一个结构的定义
set variable:将值赋予变量
print 除了显示一个变量的值外,还可以用来赋值
1
3
七.单步执行
next
不进入的单步执行
step
进入的单步执行
如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令 finish
八.函数的调用
call name 调用和执行一个函数
(gdb) call gen_and_sork( 1234,1,0 )
(gdb) call printf(―abcd‖)
$1=4
finish 结束执行当前函数,显示其返回值(如果有的话)
九.机器语言工具
有一组专用的gdb变量可以用来检查和修改计算机的通用寄存器,gdb提供了目前每一台计算机中实际使
用的 4 个寄存器的标准名字:
$pc : 程序计数器
$fp : 帧指针(当前堆栈帧)
$sp : 栈指针
$ps : 处理器状态
十.信号
gdb 通常可以捕捉到发送给它的大多数信号,通过捕捉信号,它就可决定对于正在运行的进程要做些什
么工作。例如,按 CTRL-C 将中断信号发送给 gdb,通常就 会终止 gdb。但是你或许不想中断 gdb,真正
的目的是要中断 gdb 正在运行的程序,因此,gdb 要抓住该信号并停止它正在运行的程序,这样就可以执
行某 些调试操作。
Handle 命令可控制信号的处理,他有两个参数,一个是信号名,另一个是接受到信号时该作什么。几
种可能的参数是:
nostop 接收到信号时,不要将它发送给程序,也不要停止程序。
1
4
stop 接受到信号时停止程序的执行,从而允许程序调试;显示一条表示已接受到信号的消息(禁止使
用消息除外)
print 接受到信号时显示一条消息
noprint 接受到信号时不要显示消息(而且隐含着不停止程序运行)
pass 将信号发送给程序,从而允许你的程序去处理它、停止运行或采取别的动作。
l nopass 停止程序运行,但不要将信号发送给程序。
例如,假定你截获 SIGPIPE 信号,以防止正在调试的程序接受到该信号,而且只要该信号一到达,就要
求该程序停止,并通知你。要完成这一任务,可利用如下命令:
(gdb) handle SIGPIPE stop print
请注意,UNIX 的信号名总是采用大写字母!你可以用信号编号替代信号名
如 果你的程序要执行任何信号处理操作,就需要能够测试其信号处理程序,为此,就需要一种能将信
号发送给程序的简便方法,这就是 signal 命令的任务。 该 命令的参数是一个数字或者一个名字,如
SIGINT。假定你的程序已将一个专用的 SIGINT(键盘输入,或 CTRL-C;信号 2)信号处理程序设置成
采 取某个清理动作,要想测试该信号处理程序,你可以设置一个断点并使用如下命令:
(gdb) signal 2
continuing with signal SIGINT(2)
该程序继续执行,但是立即传输该信号,而且处理程序开始运行.
十一. 原文件的搜索
search text:该命令可显示在当前文件中包含 text 串的下一行。
Reverse-search text:该命令可以显示包含 text 的前一行。
十二.UNIX 接口
shell 命令可启动 UNIX 外壳,CTRL-D 退出外壳,返回到 gdb.
十三.命令的历史
为了允许使用历史命令,可使用 set history expansion on 命令
(gdb) set history expansion on
小结:常用的 gdb 命令
1
5
backtrace 显示程序中的当前位置和表示如何到达当前位置的栈跟踪(同义词:where)
breakpoint 在程序中设置一个断点
cd 改变当前工作目录
clear 删除刚才停止处的断点
commands 命中断点时,列出将要执行的命令
continue 从断点开始继续执行
delete 删除一个断点或监测点;也可与其他命令一起使用
display 程序停止时显示变量和表达时
down 下移栈帧,使得另一个函数成为当前函数
frame 选择下一条 continue 命令的帧
info 显示与该程序有关的各种信息
jump 在源程序中的另一点开始运行
kill 异常终止在 gdb 控制下运行的程序
list 列出相应于正在执行的程序的原文件内容
next 执行下一个源程序行,从而执行其整体中的一个函数
print 显示变量或表达式的值
pwd 显示当前工作目录
pype 显示一个数据结构(如一个结构或 C++类)的内容
quit 退出 gdb
reverse-search 在源文件中反向搜索正规表达式
run 执行该程序
search 在源文件中搜索正规表达式
set variable 给变量赋值
signal 将一个信号发送到正在运行的进程
step 执行下一个源程序行,必要时进入下一个函数
undisplay display 命令的反命令,不要显示表达式
until 结束当前循环
up 上移栈帧,使另一函数成为当前函数
watch 在程序中设置一个监测点(即数据断点)
whatis 显示变量或函数类型