使用gdb进行调试
今天介绍一下gdb,如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。GDB主要帮忙你完成下面四个方面的功能:
1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3、当程序被停住时,可以检查此时你的程序中所发生的事。
4、动态的改变你程序的执行环境。
一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:
> cc -g hello.c -o hello
> g++ -g hello.cpp -o hello
如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。当你用-g把调试信息加入之后,并成功编译目标代码以后,让我们来看看如何用gdb来调试他。
启动GDB的方法有以下几种:
1、gdb <program>
program也就是你的执行文件,一般在当前目录下。
2、gdb <program> core
用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
3、gdb <program> <PID>
如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。
在启动了gdb后,就可以开始使用gdb中命令了。如果希望查看都有哪些命令,可以输入help进行查询。
下面简单演示几个小例子:
示例一:在进入函数func时,设置一个断点。可以敲入break func,或是直接就是b func
(gdb) b func
Breakpoint 1 at 0x8048458: file hello.c, line 10.
示例二:敲入b按两次TAB键,你会看到所有b打头的命令:
(gdb) b
backtracebreak bt
示例三:l(l命令相当于list,从第一行开始例出原码)
示例四:r(运行程序) n(下一步) c(Continuing)
示例五:p i 查看变量i的值
示例六:bt 查看函数堆栈
需要特别说明的是,在gdb中运行程序时,使用run命令,可能需要做以下的操作。
1、程序运行参数。
set args 可指定运行时参数。(如:set args 10 20 30 40 50)
show args 命令可以查看设置好的运行参数。
2、运行环境。
path <dir> 可设定程序的运行路径。
show paths 查看程序的运行路径。
set environment varname [=value] 设置环境变量。如:set env USER=hchen
show environment 查看环境变量。
3、工作目录。
cd <dir> 相当于shell的cd命令。
pwd 显示当前的所在目录。
4、程序的输入输出。
info terminal 显示你程序用到的终端的模式。
使用重定向控制程序输出。如:run > outfile
tty命令可以指写输入输出的终端设备。如:tty /dev/ttyb
以上就是对gdb简单的一个介绍,以后如果有机会会更详细的介绍各种功能。请大家多多指教。
设置断点break <function> 在进入指定函数时停住。C++中可以使用class::function或function(type,type)格式来指定函数名。break <linenum> 在指定行号停住。 break filename:linenum 在源文件filename的linenum行处停住 break filename:function 在源文件filename的function函数的入口处停住 break *address 在程序运行的内存地址处停住 break if i=100 表示当i为100时停住程序 info breakpoints(info break) 查看断点 设置观察点(WatchPoint)观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。我们有下面的几种方法来设置观察点:watch <expr> 为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序 rwatch <expr> 当表达式(变量)expr被读时,停住程序 awatch <expr> 当表达式(变量)的值被读或被写时,停住程序 info watchpoints 列出当前所设置了的所有观察点 删除观察点或断点clear 清除所有设置在函数上的停止点 clear <function> 清除所有设置在函数上的停止点 delete 删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。range 表示断点号的范围(如:3-7)。其简写命令为d disable disable所指定的停止点,breakpoints为停止点号。如果什么都不指定,表示disable所有的停止点。简写命令是dis. enable enable所指定的停止点,breakpoints为停止点号。 恢复程序运行和单步调试当程序被停住了,你可以用continue命令恢复程序的运行直到程序结束,或下一个断点到来。也可以使用step或next命令单步跟踪程序。continue (c)恢复程序运行,直到程序结束,或是下一个断点到来 step <count> 单步跟踪,如果有函数调用,他会进入该函数.后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。 next <count> 同样单步跟踪,如果有函数调用,他不会进入该函数 set step-mode on/off打开/关闭step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码 finish 运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息 until 或 u 当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体. nexti 或 ni 单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令。与之一样有相同功能的命令是“display/i $pc” ,当运行完这个命令后,单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码) 查看栈信息当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。当你的程序调用了一个函数,函数的地址,函数参数,函数内的局部变量都会被压入“栈”(Stack)中。你可以用GDB命令来查看当前的栈中的信息。backtrace 打印当前的函数调用栈的所有信息 frame <n> 查看某一层的信息 frame 会打印出这些信息:栈的层编号,当前的函数名,函数参数值,函数所在文件及行号,函数执行到的语句。 info f这个命令会打印出更为详细的当前栈层的信息,只不过,大多数都是运行时的内内地址。 info args 打印出当前函数的参数名及其值 info locals打印出当前函数中所有局部变量及其值。 info catch 打印出当前的函数中的异常处理信息。
以上是关于gdb的一些使用说明,都很简单。下一次打算介绍一下如何查看运行过程中变量的值和内存地址,也就算是最常用的部分了,我姑且称之为高级篇,希望大家不要见笑。 注:如果希望了解更多关于gdb的知识,请看http://blog.csdn.net/haoel/article/details/2879
使用gdb进行调试高级篇
之前写过两篇科普文章,使用gdb调试程序入门篇和中级篇,今天打算把最后的一部分写完,就是所谓的高级篇。其实很简单,也没有多复杂。只是个人认为gdb的使用,掌握到这个地方,对于常规的调试需求就已经足够了。至于更高级的应用,肯定是多多益善。但是学习工具的目的就在于提高工作效率,没有必要为了技术而技术,技术永远都只是一种工具。不知道这个观点是否会被技术迷所鄙视,呵呵。不多废话了,言归正传。
查看运行时数据
在你调试程序时,当程序被停住时,你可以使用print命令(简写命令为p),或是同义命令inspect来查看当前程序的运行数据。print命令的格式是:
print <expr>
print /<f> <expr>
<expr>是表达式,是你所调试的程序的语言的表达式(GDB可以调试多种编程语言),<f>是输出的格式,比如,如果要把表达式按16进制的格式输出,那么就是/x。
有时候,你需要查看一段连续的内存空间的值。比如数组的一段,或是动态分配的数据的大小。你可以使用GDB的“@”操作符,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度。例如,你的程序中有这样的语句:
int *array = (int *) malloc (len * sizeof (int));
于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:
p *array@len
@的左边是数组的首地址的值,也就是变量array所指向的内容,右边则是数据的长度,其保存在变量len中,其输出结果,大约是下面这个样子的:
(gdb) p *array@len
$1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}
输出格式
一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量的中的位的情况。要做到这样,你可以使用GDB的数据显示格式:
x按十六进制格式显示变量。
d按十进制格式显示变量。
u按十六进制格式显示无符号整型。
o按八进制格式显示变量。
t按二进制格式显示变量。
a按十六进制格式显示变量。
c按字符格式显示变量。
f按浮点数格式显示变量。 (gdb) p i
$21 = 101
(gdb) p/a i
$22 = 0x65
(gdb) p/c
i
$23 = 101 'e'
(gdb) p/f i
$24 =
1.41531145e-43
(gdb) p/x i
$25 = 0x65
(gdb) p/t i
$26 = 1100101
查看内存
你可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:
x/<n/f/u> <addr>
n、f、u是可选的参数。
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
<addr>表示一个内存地址。
n/f/u三个参数可以一起使用。例如:
命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。
注:关于gdb调试更多的内容,请查看http://blog.csdn.net/haoel/article/details/2883。
页:
[1]