分享

gdb调试

 happy123god 2012-08-01
 
gdb的命令很多,本文不会全部介绍,仅会介绍一些最常用的。在介绍之前,先介绍gdb中的一个非常有用的功能:补齐功能。它就如同linux下shell中的命令补齐一样。当你输入一个命令的前几个字符,然后输入tab键,如果没有其它命令的前几个字符与此相同,shell将补齐此命令。如果有其它命令的前几个字符与此相同,你会听到一声警告声,再输入tab键,shell将所有前几个字符与此相同的命令全部列出。而gdb中的补齐功能不仅能补齐gdb命令,而且能补齐参数。
本文将先介绍常用的命令,然后结合一个具体的例子来演示如何实际使用这些命令。下面的所有命令除了第一条启动gdb命令是在shell下输入的,其余都是gdb内的命令。大部分gdb内的命令都可以仅输入前几个字符,只要不与其它指令冲突。如quit可以简写为q,因为以q打头的命令只有quit。list可以简写为l,等等。
1.启动gdb
你可以输入gdb来启动gdb
程序
。gdb程序有许多参数,在此没有必要详细介绍,但一个最为常用的还是要介绍的:如果你已经编译好一个程序,我们假设文件名为hello,你想用gdb调试它,可以输入gdb hello来启动gdb并载入你的程序。如果你仅仅启动了gdb,你必须在启动后,在gdb中再载入你的程序。
2.载入程序 === file
在gdb内,载入程序很简单,使用file命令。如file hello。当然,
程序
的路径名要正确。
退出gdb === quit
在gdb的命令方式下,输入quit,你就可以退出gdb。你也可以输入'c-d'来退出gdb。
3.运行程序 === run
当你在gdb中已将要调试的程序载入后,你可以用run命令来执行。如果你的
程序
需要参数,你可以在run指令后接着输入参数,就象你在shell下执行一个需要参数的命令一样。
4.查看程序信息 === info
info指令用来查看程序的信息,当你用help info查看帮助的话,info指令的参数足足占了两个屏幕,它的参数非常多,但大部分不常用。我用info指令最多的是用它来查看断点信息。
4.1 查看断点信息
info br
br是断点break的缩写,记得gdb的补齐功能吧。用这条指令,你可以得到你所设置的所有断点的详细信息。包括断点号,类型,状态,内存地址,断点在源程序中的位置等。
4.2 查看当前源程序
info source
4.3 查看堆栈信息
info stack
用这条指令你可以看清楚程序的调用层次关系。
4.4 查看当前的参数
info args
5.列出源一段源
程序
=== list
5.1 列出某个函数
list function
.2 以当前源文件的某行为中间显示一段源程序
list linenum
5.3 接着前一次继续显示
list
5.4 显示前一次之前的源程序
list -
5.5 显示另一个文件的一段程序
list filename:function 或 list filename:linenum
6.设置断点 === break
现在我们将要介绍的也许是最常用和最重要的命令:设置断点。无论何时,只要你的
程序
已被载入,并且当前没有正在运行,你就能设置,修改,删除断点。设置断点的命令是break。有许多种设置断点的方法。如下:
6.1 在函数入口设置断点
break function
6.2 在当前源文件的某一行上设置断点
break linenum
6.3 在另一个源文件的某一行上设置断点
break filename:linenum
6.4 在某个地址上设置断点,当你调试的
程序
没有源程序是,这很有用
break *address
除此之外,设置一个断点,让它只有在某些特定的条件成立时程序才会停下,我们可以称其为条件断点。这个功能很有用,尤其是当你要在一个程序会很多次执行到的地方设置断点时。如果没有这个功能,你必须有极大的耐心,加上大量的时间,一次一次让程序断下,检查一些值,接着再让程序继续执行。事实上,大部分的断下并不是我们所希望的,我们只希望在某些条件下让程序断下。这时,条件断点就可以大大提高你的效率,节省你的时间。条件断点的命令如下,在后面的例子中会有示例。
6.5 条件断点
break ...if cond
7.其它断点操作
gdb给每个断点赋上一个整数数字,这个数字在操作断点时起到重要作用,它实际上就代表相应的断点。gdb中的断点有四种状态:
有效(enabled)
禁止(disabled)
一次有效(enabled once)
有效后删除(enabled for deletion)
在上面的四个状态有效和禁止都很好理解,禁止就是让断点暂时失效。一次有效就是当程序在此断点断下后,断点状态自动变为禁止状态。有效后删除就是当程序在此断点断下后,断点被删除。实际上,后两种状态一般不会碰到。
当你设置一个断点后,它的确省状态是有效。你可以用enable和disable指令来设置断点的状态为有效或禁止。例如,如果你想禁止2号断点,可以用下面的指令:
disable 2
相应的,如果想删除2号断点,可以有下面的指令:
delete 2
8.设置监视点 === watch
当你调试一个很大的程序,并且在跟踪一个关键的变量时,发现这个变量不知在哪儿被改动过,如何才能找到改动它的地方。这时你可以使用watch命令。简单地说,监视点可以让你监视某个表达式或变量,当它被读或被写时让
程序
断下。watch命令的用法如下:
watch expression
watch指令是监视被写的,当你想监视某个表达式或变量被读的话,需要使用rwatch指令,具体用法是一样的。要注意的是,监视点有硬件和软件两种方式,如果可能linux尽可能用硬件方式,因为硬件方式在速度上要大大快于软件方式。软件方式由于要在每次执行一条指令后都要检查所要监视的值是否被改变,因此它的执行速度会大大降低。同时它也无法设置成被读时让
程序
断下,因为读操作不会改变值,所以gdb无法检测到读操作。幸运的是,目前的pc机基本都支持硬件方式。如果你想确认一下你的机器是否支持硬件,你可以在调试程序时用watch设置一个监视点,如果gdb向你显示:
hardware watchpoint num: expr
.检查数据
最常用的检查数据的方法是使用print命令。
print exp
print指令打印exp表达式的值。却省情况下,表达式的值的打印格式依赖于它的数据类型。但你可以用一个参数/f来选择输出的打印格式。f是一个代表某种格式的字母,详细可参考输出格式一节。表达式可以是常量,变量,函数调用,条件表达式等。但不能打印宏定义的值。表达式exp中的变量必须是全局变量或当前堆栈区可见的变量。否则gdb会显示象下面的一条信息:
no symbol "varible" in current context
10.修改变量值
在调试
程序
时,你可能想改变一个变量的值,看看在这种情况下会发生什么。用set指令可以修改变量的值:
set varible=value
例如你想将一个变量tmp的值赋为10,
set tmp=10
11.检查内存值
检查内存值的指令是x,x是examine的意思。用法如下:
x /nfu addr
其中n代表重复数,f代表输出格式(见2.13),u代表每个数据单位的大小。u可以去如下值:
b :字节(byte)
h :双字节数值
w :四字节数值
g :八字节数值
因此,上面的指令可以这样解释:从addr地址开始,以f格式显示n个u数值。例如:
x/4ub 0x4000
会以无符号十进制整数格式(u)显示四个字节(b),0x4000,0x4001,0x4002,0x4003。
12.输出格式
缺省情况下,输出格式依赖于它的数据类型。但你可以改变输出格式。当你使用print命令时,可以用一个参数/f来选择输出的打印格式。f可以是以下的一些值:
'x' 16进制整数格式
'd' 有符号十进制整数格式
'u' 无符号十进制整数格式
'f' 浮点数格式
13.单步执行指令
单步执行指令有两个step和next。step可以让你跟踪进入一个函数,而next指令则不会进入函数。
14.继续执行指令
当程序被断下后,你查看了所需的信息后,你会希望
程序
执行下去,输入 continue, 程序会继续执行下去。
15.帮助指令help
在gdb中,如果想知道一条指令的用法,最方便的方法是使用help。使用方法很简单,在help后跟上指令名。例如,想知道list指令用法,输入
help list
 
 
 

tags: GDB

GDB:

backtrace命令(简写为bt) 可以查看函数调用的栈帧

可见gcc的-g选项并不是把源代码嵌入到可执行文件中的,在调试时也需要源文件。

frame命令(简写为f) 选择1号栈帧然后再查看局部变量.

info命令(简写为i)查 看函数局部变量的值.

step命令(简写为s)钻进add_range函数中去跟踪执行

 

表 10.1. gdb基本命令1



backtrace(或bt) 查看各级 函数调用及参数
finish 连续运行到当前函数返回为止,然后停下来等待命令
frame(或 f) 帧编号 选择栈帧
info(或i) locals 查看当前栈帧局部变量的 值
list(或l) 列出源代码,接着上次的位置往下列,每次列10行
list 行号 列出从第几行开始的源代码
list 函数名 列出某个函数的源代码
next(或 n) 执行下一行语句
print(或p) 打印表达式的值,通过表达式可以修改变量的值或者调用函数
quit(或q) 退出gdb调 试环境
set var 修改变量的值
start 开始执行程序,停在main函数第一行语句前面等待命令
step(或 s) 执行下一行语句,如果有函数调用则进入到函数中

 

表 10.2. gdb基本命令2

命 令 描述
break(或b) 行号 在某一行设置 断点
break 函数名 在某个函数开头设置断点
break ... if ... 设置条件断点
continue(或c) 从当前位置开始 连续运行程序
delete breakpoints 断点号 删除断点
display 变量名 跟踪查看某个变量,每次停下来都显示它的值
disable breakpoints 断点号 禁用断点
enable 断点号 启用断点
info(或 i) breakpoints 查看当前设置了哪些断点
run(或r) 从头开始 连续运行程序
undisplay 跟踪显示号 取消跟踪显示

 

表 10.3. gdb基本命令3

命 令 描述
watch 设置观察点
info(或 i) watchpoints 查看当前设置了哪些观察点
x 从某个位置开始打印存储单元的内容,全部当成字节来看,而不区分哪个字节属于哪个变量

 

查看某个变量是什么时候变化的,用观察点来跟踪。

 (gdb) x/7b input
0xbfb8f0a7: 0x31 0x32 0x33 0x34 0x35 0x00 0x00

x命令打印指定存储单元的内容。7b是打印格式,b表示每个字节一组,7表示打印7组,从input数组的第一个字节开始连续打印7个字节。前5个字节是input数组的存储单元,打印的正是十六进制 ASCII码的'1''5', 第6个字节是写出界的'\0'

字节到底是什么时候变的?可以用观察点(Watchpoint)来跟 踪

我们知道断点是当程序执行到某一代码行时中断,而观察点是当程序访问某个存储单元时中断,如果我们不知道某个存储单元是在哪里被改动的,这时候观察点尤其有用。

如果某个函数的局部变量发生访问越界,有可能并不立即产生段错误,而是在函数返回时产生段错误

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多