Gdb是Linux下一款功能强大的c/c++程序调试工具
一般来说,gdb主要提供以下功能
1. 设置断点(断点可以是条件表达式),使程序在制定的代码上暂停执行,便于观察
2. 单步执行程序,便于调试。
3. 查看程序中变量值得变换。
4. 动态改变程序的执行环境
5. 分析崩溃程序产生的core文件
gdb常用命令
命令 | 含义描述 |
file | 装入想要调试的可执行文件 |
run | 执行当前被调试的程序 |
kill | 终止正在调试的程序 |
step | 执行 一行源代码而且进入函数内部 |
next | 执行一行源代码但不进入函数内部 |
backtrace | 回溯跟踪 |
fram n | 定位到发生错误的代码段,n为backtrace命令输出结果中的行号 |
break | 在代码里设置断点,这将使程序执行到这里时被挂起 |
| 打印表达式或变量的值,或打印内存中某个变量开始的一段连续区域的值,还用来对变量进行赋值 |
display | 设置自动显示的表达式或变量,当程序挺住或在单步跟踪时,这些变量会自动显示其当前值 |
list | 列出产生可执行文件的源代码的一部分 |
|
|
gdb调试初步
程序代码:
Run
通过run命令让程序开始在gdb的监控下运行
通过上图可知具体发生问题的地方是在调用_IO_vfscanf_internal(),通过gdb提供的回溯跟踪命令backtrace得到更有价值的信息。
使用frame n命令可以定位到发生错误的代码段,该命令后面跟着的数值可以在backtrace命令输出结果中的行首找到。
gdb的使用详解
使用断点
断点指出了gdb将要在该点处中断程序的运行,从而便于程序员单步跟踪代码。
break(简称b)
命令 | 含义描述 |
break <function> | 在进入指定函数时停住,C++中可以使用class::function或function(type,type)格式来指定函数名 |
break <linenum> | 在指定行号停住 |
break +offset | 在当前行号的前面的offset行停住。offset为自然数 |
break -offset | 在当前行号的后面的offset行停住 |
break filename:linenum | 在源文件filename的linenum行停住 |
break filename:function | 在源文件filename的function函数的入口处停住 |
break *address | 在程序运行的内存地址处停住 |
break | 该命令没有参数时,表示在下一条指令处停住 |
break ..if<condition> | Condition表示条件,在条件成立时停住。比如在循环体中,可以设置break if i=100, 表示当i为100时停住程序 |
gdb常用命令的参数
命令 | 含义描述 |
<linenum> | 行号 |
<function> | 函数名 |
<+offset> | 当前行号的正偏移量 |
<-offset> | 当前行号的负偏移量 |
<filename:linenum> | 某个文件的某一行 |
<filename:function> | 某个文件的某个子函数 |
<*address> | 程序运行时的语句在内存中的地址 |
将断点定在main函数
使用run(简称r)命令开始执行程序
使用单步调试命令step(简称s)来跟踪程序,它一次只执行程序中的一行代码。
查看运行时数据
print命令
当使用gdb的print命令查看程序运行时的数据时,每一个print都会被gdb记录下来。Gdb会以$1,$2,$3,…这样的方式为每一个print命令编上号。
要注意print命令的表达式中两个具有特殊意义的符号,$和$$.$表示给定序号的前一个序号,而$$表示给定序号的向前两个的序号,如果不给定序号,gdb将默认当前序号为给定序号
Print的输出格式
符号 | 含义 |
x | 按十六进制格式显示变量 |
d | 按十进制显示变量 |
u | 按十六进制格式显示无符号整形 |
o | 按八进制显示变量 |
t | 按二进制显示变量 |
a | 按十六进制显示变量 |
c | 按字符格式显示变量 |
f | 按浮点数格式显示变量 |
自动显示命令display
可以设置一些自动显示的变量,当程序挺住使,或是在单步跟踪时,这些变量会自动显示。
display <expr>
display/<fmt> <expr>
display/<fmt> <addr>
expr是一个表达式,fmt表示显示的格式,addr表示内存地址。
display/I $pc
$pc是gdb的环境变量,表示指令的地址,/i则表示输出格式为机器指令码。
Display相关命令
命令 | 含义藐视 |
undisplay <dnums…> delete display<dnums…> | 删除自动显示,dnums为已设置好了的自动显示编号。如果要同时删除几个编号,可以用空格分隔:如果要删除一个范围内的编号,可以用减号表示 |
disable display<dnums..> enable display<dnums…> | 不删除自动显示的设置,而只是让其失效或回复 |
Info display | 查看display设置的自动显示的信息。 |
查看内存
可以使用examine命令(简称x)来查看内存地址中的值
x/<n/f/u> <addr>
n表示显示内存的长度
f表示显示的格式
u表示从当前地址往后请求的字节数,如不指定的话,gdb默认是4个bytes
gdb环境变量
set $变量名
查看环境变量
Show convenience
查看寄存器
当前运行的指令地址(IP),程序的当前堆栈地址(SP)
命令 | 含义藐视 |
info registers | 查看寄存器的情况 |
info all-registers | 查看所有寄存器的情况 |
info registers<regname..> | 查看所指定的寄存器的情况,rename表示寄存器名,多个寄存器之间用逗号隔开 |
查看源程序
List命令
命令 | 含义描述 |
list <linenum> | 显示程序第linenum行周围的源程序 |
list <function> | 显示名为function的函数的源程序 |
list | 显示当前行后面的源程序 |
list - | 显示当前行前面的源程序。一般是显示当前行的上5行和下5行 |
list + | 向后显示源代码 |
set listsize | 查看当前listsize的设置 |
show listsize | 设置一次显示源程序的行数 |
list <first>,<last> | 显示从first行到last行之间的源代码 |
List ,<last> | 显示从当前行到last行之间的源代码 |
源代码的内存
可以使用info line命令来查看源代码在内存中的地址。
disassemble可以查看源程序当前执行时的机器码,这个命令会把当前内存中的指令dump出来。
Disassemble是一个非常有用的命令,对于那些熟悉汇编语言的c程序员,他们在编写大型程序的时候,往往要考虑系统硬件内存资源的分配等问题,这时候利用反汇编来查看当前程序执行的机器码,对于程序的检错纠错是很有帮助的。
改变程序的执行
一旦使用gdb挂上被调试程序,当程序执行起来后,可以根据自己的调试思路来动态地在gdb中更改当前被调试程序的运行路线或其变量的值。
修改变量的值
print命令还有一个功能是修改被调试程序中运行时的变量值
print x=8
跳转执行
一般来说,被调试程序会按照程序代码的运行顺序依次执行,gdb提供了乱序执行的功能。Gdb可以修改程序的执行顺序,可以让程序执行随意跳跃。
jump <linespec>
指定下一条语句的运行点。<linespec>可以是文件的行号,可以是file:line格式,可以是+num这种偏移量格式。
jump <address>
产生信号量
使用signal命令可以产生一个信号量给被调试的程序。如中断信号CTRL+C。
signal <signal>
linux的系统信号量通常从1-15.
强制函数返回
如果调试断点在某个函数中,还有语句没有执行完,可以使用return命令强制函数忽略还没有执行的语句并返回。
return
return <expression>
使用return命令取消当前函数的执行,并立即返回。如果指定了<expression>,那么该表达式会被当做函数的返回值。
强制调用函数
强制调用函数使用call命令。
call <expr>
表达式中也可以是函数,已达到强制调用函数的目的,显示函数的返回值,如果返回值是void,那么就不显示。
Gdb的语言环境命令
命令 | 含义描述 |
show language | 查看当前的语言环境 |
info frame | 查看当前函数的程序语言 |
info source | 查看当前文件的程序语言 |