简介

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

一般来说,GDB主要帮忙你完成下面四个方面的功能:

    1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
    2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
    3、当程序被停住时,可以检查此时你的程序中所发生的事。
    4、动态的改变你程序的执行环境。

从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。让我们一一看来。

命令

GDB控制

r 开始运行程序直到断点.

continue  :   继续运行程序直到下一个断点(类似于VS里的F5)

next  :  逐过程步进,不会进入子函数(类似VS里的F10)

setp  :  逐语句步进,会进入子函数(类似VS里的F11)

until    : 运行至当前语句块结束

finish  :  运行至函数结束并跳出,并打印函数的返回值(类似VS的Shift+F11)

return	: 强制从当前函数返回

quit(q) 退出

kill [filename]终止正在调试的程序

load [filename] : 动态载入一个可执行文件到调试器

make  : 使你能不退出 gdb 就可以重新产生可执行文件

shell [...]: 使你能不离开 gdb 就执行 UNIX shell 命令

list 显示当前位置的上下文
list [linenum]/[filename:linenum]  

变量显示

print(p): 打印变量或表达式结果
print [variable]
print [function]
whatis/ptype   [variable]: 显示变量的值和类型

断点控制

catch让程序在发生某种事件(fork、异常throw、异常catch、动态库加载等)的时候停止运行
eg: catch fork

break 在进入指定函数时停住,C++中可以使用class::function或function(type,type)格式来指定函数名

break [linenum] : 在指定行号停住

break [filename:linenum]: 在指定文件指定行号停下

break [function] : 在指定函数停下

break [filename:linenum]: 在指定文件的指定函数停下

break *[address] : 在程序运行的内存地址处停下

break if [condition] : condition表示条件,在条件成立时停住。比如在循环体中,可以设置break if i=100,表示当i为100时停住程序

delete [breakpoints] [range…]: 删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。range 表示断点号的范围(如:3-7)。其简写命令为d,比删除更好的一种方法是disable停止点。disable了的停止点,gdb不会删除,当还需要时,enable即可,就好像回收站一样

clear [line/function]: 删除一个断点,这个命令需要指定代码行或者函数名作为参数,若不指定则删除所有的

disable	[n] : 禁止断点功能,这个命令需要禁止的断点在断点列表索引值作为参数

enable [n] 

xbreak	在当前函数的退出的点上设置一个断点

condition [n] [expression] : 在断点n满足expression时停止

ignore [n] [count]   : 	忽略某个断点制定的次数。例:ignore 4 23 忽略断点4的23次运行,在第24次的时候中断

info break[n] : 断点号为n的断点

info b : 所有断点

变量赋值与监测

watch [variable] : 使你能监视一个变量的值而不管它何时被改变

rwatch [variable] :  指定一个变量,如果这个变量被读,则暂停程序运行,在调试器中显示信息,并等待下一个调试命令。参考rwatch和watch命令

awatch [variable] : 指定一个变量,如果这个变量被读或者被写,则暂停程序运行,在调试器中显示信息,并等待下一个调试命令。参考rwatch和watch命令

set [variable] : 设置变量的值。例如:set nval=54 将把54保存到nval变量中

内存检测

x/[n/f/u] [addr]

使用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会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

表示一个内存地址。

n/f/u三个参数可以一起使用。例如:

命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。

输出格式

一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量的中的位的情况。要做到这样,你可以使用GDB的数据显示格式:

上面的u可以替换成:

d 按十进制格式显示变量

x 按十六进制格式显示变量

a 按十六进制格式显示变量

u 按十进制格式显示无符号整型

o 按八进制格式显示变量

t 按二进制格式显示变量

c 按字符格式显示变量

f 按浮点数格式显示变量

s 按字符串格式显示变量

i 按指令地址显示变量(汇编)

h可以替换成:

b表示单字节,h表示双字节,w表示四字 节,g表示八字节

寄存器与汇编

info registers [寄存器] : 查看寄存器值,后面不跟寄存器的话就是查看所有寄存器

disassemble \m : 查看当前的汇编代码

stepi : 汇编代码的step

nexti : 汇编代码的next

set $[寄存器]=[value] :设置寄存器值

x/[n/f/u] $[寄存器] :把寄存器中的值作为地址,查看地址上的值


窗口

tui :  GUI显示
layout:用于分割窗口,可以一边查看代码,一边测试:
layout src:显示源代码窗口
layout asm:显示反汇编窗口
layout regs:显示源代码/反汇编和CPU寄存器窗口
layout split:显示源代码和反汇编窗口
Ctrl + L:刷新窗口

专题

栈帧溢出

bt(Backtrace) :  查看堆栈情况 ,可以用来调试栈帧溢出的情况

frame n|f n :查看其调用函数的信息,n为栈的层次,然后可以用其他命令(info)查看此级别的变量信息

多线程多进程

1、 设置follow-fork-mode (fork追踪模式)以及detach-on-fork(指示GDB在fork之后是否断开某个进程的调试)即可。

这两个参数的设置命令分别是:set follow-fork-mode [parent|child],set detach-on-fork [on|off]。两者结合起来构成了GDB的调试模式:

follow-fork-mode  detach-on-fork    说明
    parent              on          GDB默认的调试模式:只调试主进程
    child               on          只调试子进程
    parent              off         同时调试两个进程,gdb跟主进程,子进程block在fork位置
    child               off         同时调试两个进程,gdb跟子进程,主进程block在fork位置

2、 利用info threads/inferiors 来查看线程/进程情况
3、 thread [n] 切换线程
4、 inferior [n] 切换进程
5、 set scheduler-locking on/off 打开/冻结 其他线程,只执行当前所在线程

为停止点设定运行命令

可以使用gdb提供的command命令来设置停止点的运行命令。也就是说,当运行的程序在被停住时,我们可以让其自动运行一些别的命令,这很有利行自动化调试。

commands [bnum]
... command-list ...
end

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


break foo if x>0
commands
printf "x is %d/n",x
continue
end

断点设置在函数foo中,断点条件是x>0,如果程序被断住后,也就是一旦x的值在foo函数中大于0,gdb会自动打印出x的值,并继续运行程序。
如果要清除断点上的命令序列,那么只要简单地执行一下commands命令,并直接在输入end就行了。