本文将介绍gdb
的最基本的使用方法,其中的难点——多线程调试、堆栈信息分析和core
文件分析将放在下一节来讲述。
1.使用gdb的前提
gcc
是Linux
系统、Windows
系统的cygwin
下最常使用的C语言
编译器。
$ gcc -g 源代码文件名
如果追加了-g
编译选项,会在最后生成的可执行文件中嵌入一些用于捕捉和输出程序当前程序运行状态的代码,它们可以帮助我们更好地调试程序,但同时也增加了文件大小、降低运行效率。
2.启动gdb环境
$ gdb 可执行文件名
注意:这样只是指定了要调试的对象文件并启动了gdb
环境而已,而并没有真正地开始运行程序。
3.开始运行程序
(gdb) r
r
就是run
的省略。通过上面的命令,我们可以开始运行在启动gdb
环境时指定了的程序。如果想要传输启动参数,直接在r
后面加上参数1, 参数2, 参数3,……
即可。
4.退出gdb环境
(gdb) q
q
就是quit
的缩略。
5.设置断点
当程序运行到断点时,会自动停止,此时可以输出当前程序的相关信息,帮助我们更好地调试程序。
(gdb) b 行号
(gdb) b 函数名
(gdb) b 文件名:行号
b
就是break
的缩略。
6.顺序执行
①单步执行,如果当前是一个函数调用语句,则直接执行下一条语句(不进入函数内部)。
(gdb) n
n
是next
的缩略。
②单步执行,如果当前是一个函数调用语句,则进入该函数内部。
(gdb) s
s
是step
的缩略。
③继续运行程序,会在遇到断点后再次暂停运行。如果没有遇到断点,就会一直运行到结束。
(gdb) c
c
是continue
的缩略。
7.输出当前某个变量的值
(gdb) p 变量名
(gdb) p *指针名
(gdb) p &内存地址
p
是print
的缩略。
print
命令可以在后面附加/format
选项,用于指定输出的格式。
语法格式 | 含义 |
---|---|
o | 8进制表示 |
x | 16进制表示 |
t | 2进制表示 |
f | 浮点数表示 |
d | 有符号10进制表示 |
u | 无符号10进制表示 |
c | 字符 |
a | 内存地址 |
比如说,我们想以二进制形式打印变量var
当前的值,可以这么做:
(gdb) p/t var
8.查看更详细的信息
①查看某个变量的类型
whatis 变量名
或者
ptype 变量名
②查看当前设定的所有断点的信息
info b
③查看当前函数调用的堆栈信息
info stack
④查看当前的线程信息
info Thread
⑤查看当前设定的所有观察点的信息
info watchpoints
关于观察点的概念及其使用,可以查看第11
点的内容。
⑥显示所有当前调用栈的所有变量
(gdb) info locals
9.跳转
①跳转到指定行,再执行
jump <linespec>
其中的<linespec>
可以是文件的行号,可以是file:line
格式,可以是+num
这种偏移量格式。
②跳转并执行指定内存地址的代码
jump *内存地址
注意,jump
命令不会改变当前的程序栈中的内容。
10.设置条件断点
下面的程序对file.cpp
文件的function
函数设置了一个断点(gdb
会自动分配它一个断点编号
=1
),而且我们规定只有变量x
的值为1
时才执行中断。
(gdb) break file.cpp:function
(gdb) condition 1 x==1
(gdb) run
如果我们想消除断点的条件,可以这么做:
(gdb) condition 1
上面的1
是指定断点编号为1
的断点。
11.设置观察点
如果我们想实现下面这样的功能:“当变量i不等于0时执行中断”,就需要用到观察点这个功能了。
1.watch exp
:当表达式exp的值有变化时,马上停住程序;
2.rwatch v
:当变量v的值被读时,马上停住程序;
3.awatch v
:当变量v的值被读或被写时,马上停住程序。
所以,对于“当变量i
不等于0
时执行中断”这样的需求,我们可以这么做:
(gdb) break file.cpp:function
(gdb) run
(gdb) delete → break pointをすべて削除
(gdb) watch i==0 → i==0 以外の時にストップ
(gdb) c
12.改变某个变量的值
(gdb) set var 变量名 = 值
甚至我们可以利用它来指定运行时参数。
(gdb) set args 10 20 30 40 50
上面的命令没有var
关键字,是因为args
并不是程序本身声明的变量。
虽然在某些情况下,设置程序本身的变量的值可以省去var
关键字,但是为了保险起见还是建议不要省略var
。
熟悉汇编的人都知道,程序运行时,有一个叫pc
的寄存器用于保存当前代码所在的内存地址。于是,你可以使用set $pc
来更改跳转执行的地址。如:
set $pc = 0x485
13.声明辅助变量
像$pc
这样带$号
的变量一般就是gdb
为了调试方便自己引入的变量,当然我们也可以定义自己的辅助变量。
(gdb) set $ymm="yang" #定义辅助变量ymm
(gdb) whatis $ymm #查看变量类型
type = char [5]