* 设置断点;
* 监视程序变量的值;
* 程序的单步执行;
* 修改变量的值。
在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量:
CFLAGS = -g
运行 gdb 调试程序时通常使用如下的命令:
gdb progname
在 gdb 提示符处键入help,将列出命令的分类,主要的分类有:
* aliases:命令别名
* breakpoints:断点定义;
* data:数据查看;
* files:指定并查看文件;
* internals:维护命令;
* running:程序执行;
* stack:调用栈查看;
* statu:状态查看;
* tracepoints:跟踪程序执行。
键入 help 后跟命令的分类名,可获得该类命令的详细清单。
在gdb中用break命令来设置断点,设置断点的方法包括:
break <function>
break <linenum>
break +offset / break -offset
break filename:linenum
break filename:function
break *address
break
break ... if <condition>
“...”可以是上述的break <linenum>
、break +offset / break –offset
中的参数,condition表示条件,在条件成立时停住。比如在循环体中,可以设置break if i=100,表示当i为100时停住程序。
tbreak 设置临时断点 到达后自动删除 用法同break
注:断点管理
1. 显示当前gdb的断点信息:
(gdb) info break
他会以如下的形式显示所有的断点信息:
Num Type Disp Enb Address What
1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155
2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168
(gdb)
2.删除指定的某个断点:
(gdb)delete breakpoint 1
该命令将会删除编号为1的断点,如果不带编号参数,将删除所有的断点
(gdb) delete breakpoint
3.禁止使用某个断点
(gdb)disable breakpoint 1
该命令将禁止断点 1,同时断点信息的 (Enb)域将变为 n
4.允许使用某个断点
(gdb)enable breakpoint 1
该命令将允许断点 1,同时断点信息的 (Enb)域将变为 y
5.清除原文件中某一代码行上的所有断点
(gdb)cleannumber
注:number 为原文件的某个代码行的行号
例如:
四显示数据
1,print(p)命令
有一下几种格式
print(p) 变量名/数组名 打印变量值/数组所有值
print(p)函数调用 打印函数执行结果
print(p)指针 打印指针地址和指向的内容
print(p)表达式
print(p)/输出的格式 表达式
在表达式中,有几种GDB所支持的操作符,它们可以用在任何一种语言中,“@”
是一个和数组有关的操作符,“::”
指定一个在文件或是函数中的变量,“{<type>} <addr>”
表示一个指向内存地址<addr>
的类型为type的一个对象。
当需要查看一段连续内存空间的值的时间,可以使用GDB的“@”
操作符,“@”
的左边是第一个内存地址,“@”
的右边则是想查看内存的长度。例如如下动态申请的内存:
int *array = (int *) malloc (len * sizeof (int));
在GDB调试过程中这样显示出这个动态数组的值:
p *array@len
print的输出格式包括:
- x 按十六进制格式显示变量。
- d 按十进制格式显示变量。
- u 按十六进制格式显示无符号整型。
- o 按八进制格式显示变量。
- t 按二进制格式显示变量。
- a 按十六进制格式显示变量。
- c 按字符格式显示变量。
- f 按浮点数格式显示变量。
$1,$2,$3 …
这样的方式为每一个print命令编号。我们可以使用这个编号访问以前的表达式,如$1
。
(gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值
watch <expr>
:为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。
rwatch <expr>
:当表达式(变量)expr被读时,停住程序。
awatch <expr>
:当表达式(变量)的值被读或被写时,停住程序。
info watchpoints
:列出当前所设置了的所有观察点。 下面演示了观察i并在连续运行next时一旦发现i变化,i值就会显示出来的过程:
(gdb) whatis p
type = int *
我们可以使用examine命令(缩写为x)来查看内存地址中的值。examine命令的语法如下所示:
x/<n/f/u><addr>
<addr>
表示一个内存地址。“x/”
后的n、f、u都是可选的参数,
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容;
f 表示显示的格式,
如果地址所指的是字符串,那么格式可以是s,
如果地址是指令地址,那么格式可以是i;
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4字节。u参数可以被一些字符代替:
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节。
当我们指定了字节长度后,GDB会从指定的内存地址开始,读写指定字节,并把其当作一个值取出来。n、f、u这3个参数可以一起使用,例如命令“x/3uh 0x54320”
表示从内存地址0x54320开始以双字节为1个单位(h)、16进制方式(u)显示3个单位(3)的内存。 ==
五 continue(n)
继续执行 直到结束或下一个断点处 可配合ignore命令使用
ignore[断点号]<num> 执行时忽略对应断点num次
六单步执行命令
next(n)的单步不会进入函数的内部
step(缩写s)命令则在单步执行一个函数时,会进入其内部
step <count>
单步跟踪,如果有函数调用,则进入该函数(进入函数的前提是,此函数被编译有debug信息)。step后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。
next <count>
set step-mode
finish
until (缩写u)
stepi(缩写si)和nexti(缩写ni)
七set命令
nfo registers
(查看除了浮点寄存器以外的寄存器)
info all-registers
(查看所有寄存器,包括浮点寄存器)
info registers <regname ...>
(查看所指定的寄存器)
要查看断点信息,可以使用如下命令:info break
列出当前所设置的所有观察点,使用如下命令:info watchpoints
查看有哪些信号正在被GDB检测,使用如下命令:info signals
info handle
也可以使用info line命令来查看源代码在内存中的地址。info threads可以看多线程。info line后面可以跟行号、函数名、文件名:行号、文件名:函数名等多种形式
help NAME 显示指定命令的帮助信息。
info break 显示当前断点清单,包括到达断点处的次数等。
info files 显示被调试文件的详细信息。
info func 显示所有的函数名称。
info local 显示当函数中的局部变量信息。
info prog 显示被调试程序的执行状态。
info var 显示所有的全局和静态变量名称。
info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程。
thread ID 切换当前调试的线程为指定ID的线程。
break thread_test.c:123 thread all 在所有线程中相应的行上设置断点
thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command。
thread apply all command 让所有被调试线程执行GDB命令command。
set scheduler-locking off|on|step 估计是实际使用过多线程调试的人都可以发现,在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这个需求。off 不锁定任何线程,也就是所有线程都执行,这是默认值。 on 只有当前被调试程序会执行。 step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。
gdb对于多线程程序的调试有如下的支持:
- 线程产生通知:在产生新的线程时, gdb会给出提示信息
(gdb) r
Starting program: /root/thread
[New Thread 1073951360 (LWP 12900)]
[New Thread 1082342592 (LWP 12907)]---以下三个为新产生的线程
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]
- 查看线程:使用info threads可以查看运行的线程。
(gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
注意,行首的蓝色文字为gdb分配的线程号,对线程进行切换时,使用该该号码,而不是上文标出的绿色数字。
另外,行首的红色星号标识了当前活动的线程
- 切换线程:使用 thread THREADNUMBER 进行切换,THREADNUMBER 为上文提到的线程号。下例显示将活动线程从 1 切换至 4。
(gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0 0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
后面就是直接在你的线程函数里面设置断点,然后continue到那个断点,一般情况下多线程的时候,由于是同时运行的,最好设置 set scheduler-locking on
这样的话,只调试当前线程