gdb在程序开发中的应用

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。

一般来说,GDB主要帮助你完成下面五个方面的功能:
1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3、当程序被停住时,可以检查此时你的程序中所发生的事。
4、动态的改变你程序的执行环境。
5、调试程序的段错误(这个功能很好用)

启动gdb

1gdb <program>
program
也就是你的执行文件,一般在当然目录下。

2gdb <program> core
gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。

3gdb <program> <PID>
如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程IDgdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。或者是进入gdb后,通过attach PID命令,将调试进程加入到gdb中。

gdb启动时常用开关选项-symbols <file> -s <file>从指定文件中读取符号表。-se file从指定文件中读取符号表信息,并把他用在可执行文件中。-core <file> -c <file>调试时core dumpcore文件。-directory <directory> -d <directory>加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径。
 

设置断点

break <function> 在进入指定函数时停住。C++中可以使用class::functionfunction(type,type)格式来指定函数名
break <linenum> 在指定行号停住
break +offset

break -offset

在当前行号的前面或后面的offset行停住。offset为自然数
break filename:linenum 在源文件filenamelinenum行处停住
break filename:function 在源文件filenamefunction函数的入口处停住
break *address 在程序运行的内存地址处停住
break break命令没有参数时,表示在下一条指令处停住
break … if <condition> 可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置break if i=100,表示当i100时停住程序
info breakpoints [n]

info break [n]

查看断点时,可使用 info 命令,如下所示:(注: n 表示断点号)

 

维护断点

观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。我们有下面的几种方法来设置观察点:
watch <expr> 为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。
rwatch <expr> 当表达式(变量)expr被读时,停住程序。
awatch <expr> 当表达式(变量)的值被读或被写时,停住程序。
info watchpoints 列出当前所设置了的所有观察点。
catch <event> 和tcatch <event> ,用help catch和help tcatch来看具体用法。

在gdb中,如果觉得设置的断点已经没有用处了,可以使用delete clair disable|enable 对断点进行操作

clear 清除所有的已定义的停止点。
clear <function>,clear <filename:function>清除所有设置在函数上的停止点。
clear <linenum>,clear <filename:linenum> 清除所有设置在指定行上的停止点。
delete [breakpoints] [range...] 删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。range 表示断点号的范围(如:3-7)。其简写命令为d。

比删除更好的方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可.

disable [breakpoints] [range...]disable所指定的停止点,breakpoints为停止点号。如果什么都不指定,表示disable所有的停止点。简写命令是dis.
enable [breakpoints] [range...]enable所指定的停止点,breakpoints为停止点号。
enable [breakpoints] once range...enable所指定的停止点一次,当程序停止后,该停止点马上被GDB自动disable。
enable [breakpoints] delete range...enable所指定的停止点一次,当程序停止后,该停止点马上被GDB自动删除。

可以使用b <function_name> if condition 来设置条件断点,当条件成立时,程序自动停止;

同时我们可以使用condition命令来修改条件(只有break和watch命令支持if,catch目前暂不支持if);

condition <bnum> <expression> 修改断点号为bnum的停止条件为expression。
condition <bnum> 清除断点号为bnum的停止条件。
还有一个比较特殊的维护命令ignore,你可以指定程序运行时,忽略停止条件几次。
ignore <bnum> <count> 表示忽略断点号为bnum的停止条件count次。
为停止点设置运行命令,我们可以使用gdb提供的command 来为停止点处设置运行命令,即当程序运行到断点处时,会自动运行先前使用command来设置的命令,这样很方便来进行自动化调试;
commands [bnum]... command-list ...end

为断点号bnum指写一个命令列表。当程序被该断点停住时,gdb会依次运行命令列表中的命令。
例如:

break foo if x>0 command sprintf "x is %d\n",x continue end

恢复程序执行与单步调试

当程序运行到断点处时,程序被挺住,这时可以使用continue命令使程序继续运行,next或者step命令进行单步跟踪

continue [ignore-count]c [ignore-count]fg [ignore-count]

恢复程序运行,直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断点次数

step

单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是,此函数被编译有debug信息,后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住

set step-mode,set step-mode on

打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码

next

单步运行count 条指令,count默认值为1

finish

运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息。

until

可以运行程序直到退出循环体

stepi 或 si,nexti 或 ni
单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令

打印信息

1、当程序停在你设置的断点处时,你首先需要看的是函数调用的过程即函数调用栈,及每层栈中函数的名称、参数和局部变量等信息,这时可以用gdb提供的backtrace(bt)来查看函数调用栈信息。backtrace <n>, bt <n> n是一个正整数,表示只打印栈顶上n层的栈信息。backtrace <-n> ,bt <-n> -n表一个负整数,表示只打印栈底下n层的栈信息。

2、如果你要查看某一层的信息,你需要在切换当前的栈,一般来说,程序停止时,最顶层的栈就是当前栈,如果你要查看栈下面层的详细信息,首先要做的是切换当前栈,此时可以用frame命令来进行切换。frame <n> 是一个从0开始的整数,是栈中的层编号。比如:frame 0,表示栈顶,frame 1,表示栈的第二层。up 表示向栈的上面移动n层,可以不打n,表示向上移动一层。down 表示向栈的下面移动n层,可以不打n,表示向下移动一层。

3、当切换到某个某层frame时,可以使用info命令来查看当前函数的具体信息。info frame 显示当前frame的详细信息;info args 显示函数的参数的详细信息;info locals 打印出当前函数中所有局部变量及其值;info catch 打印出当前的函数中的异常处理信息。

4、GDB 可以打印出所调试程序的源代码,当然,在程序编译时一定要加上-g的参数,把源程序信息编译到执行文件中,具体可以使用list命令来查看源代码程序。list + 参数一般来说在list后面可以跟以下参数:

  • 行号: <+offset> 当前行号的正偏移量  <-offset> 当前行号的负偏移量;
  • 哪个文件的哪一行
  • 函数名
  • 哪个文件中的哪个函数
  • <*address> 程序运行时的语句在内存中的地址

5、在用gdb调试程序时,当程序运行到之前设置的断点时,很容易想到的操作就是查看当前变量的值,在gdb中最常用的命令就是print(简写p),具体格式如下:

print <expr>
print/f <expr>
f代表输出的格式: x 按十六进制格式显示变量 ,d 按十进制格式显示变量, u 按十六进制格式显示无符号整型, o 按八进制格式显示变量, t 按二进制格式显示变量, a 按十六进制格式显示变量 ,c 按字符格式显示变量, f 按浮点数格式显示变量。
6、查看寄存器
info registers 查看寄存器的情况。(除了浮点寄存器)
info all-registers 查看所有寄存器的情况。(包括浮点寄存器)
info registers %eax 查看所指定的寄存器的情况
7、 在GCC编译程序的时候,加上 -ggdb3 参数,这样,你就可以调试宏了。
  • info macro_name – 查看这个宏在哪些文件里被引用了,以及宏定义是什么样的。
  • macro_name – 查看宏展开的样子。

8、在gdb中,你可以设置当程序停在断点处时,自动显示变量的内容,即display命令,使用如下:

display <expr>
display/<fmt> <expr>
display/<fmt> <addr>
expr是一个表达式,fmt表示显示的格式,addr表示内存地址
一个非常有用的命令,显示源码与机器码的对应:
display/i $pc
$pc是GDB的环境变量,表示着指令的地址,/i则表示输出格式为机器指令码,也就是汇编。于是当程序停下后,就会出现源代码和机器指令码相对应的情形。
undisplay
delete display
disable display
enable display
info display 查看display设置的自动显示的信息

你可能感兴趣的:(gdb,调试,程序开发)