1. 启用、禁用断点
如果一个断点被禁用,则该断点不会被命中,但是它仍然会在断点列表中显示。我们仍然可以通过 info b
来查看被禁用的断点,也可以通过启用断点命令来重新启用被禁用的断点。
禁用断点的语法如下:
disable 断点编号
启用断点的语法如下:
enable 断点编号
假设我们已经设置了 3 个断点,现在要把 2 号断点暂时禁用,可以使用以下命令来禁用 2 号断点:
disable 2
如果要启用 2 号断点,可以使用以下命令:
enable 2
在禁用断点后,断点的 Enb
标志变成 n
,启用以后又恢复为 y
。
也可以对一个范围内的断点执行启用或禁用操作,比如禁用编号为 4~10
的断点,则可以使用下述命令:
disable 4-10
启用断点也是一样的。例如要启用编号为 4~10 的断点,则可以使用下述命令:
enable 4-10
示例代码
#include <iostream>
#include <string>
void fun_test(int a, const char *str)
{
printf("a is %d, str is %s\n", a, str);
}
int add(int a, int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
int ret = add(3, 5);
std::cout << "ret is " << ret << std::endl;
fun_test(10, "test");
}
示例过程
(gdb) b demo.cpp:6
Breakpoint 1 at 0x969: file demo.cpp, line 6.
(gdb) b demo.cpp:11
Breakpoint 2 at 0x990: file demo.cpp, line 11.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
2 breakpoint keep y 0x0000000000000990 in add(int, int)
at demo.cpp:11
(gdb) disable 2
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
2 breakpoint keep n 0x0000000000000990 in add(int, int)
at demo.cpp:11
(gdb) disable 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep n 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
2 breakpoint keep n 0x0000000000000990 in add(int, int)
at demo.cpp:11
(gdb) enable 1-2
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
2 breakpoint keep y 0x0000000000000990 in add(int, int)
at demo.cpp:11
(gdb)
2. 启用断点一次
在启用断点时,可以只启用一次,命中一次后会自动禁用,不会再次命中。它与临时断点相似,临时断点只会命中一次,命中一次之后就会自动删除。启用断点一次的不同之处在于断点启用后,虽然只会命中一次,但是不会被删除,而是被禁用。
启用断点一次的语法如下:
enable once 断点编号
比如我们为函数 test_fun
设置了一个断点,然后禁用了该断点。假设该断点编号为 1,如果只启用一次,则可以使用下述命令启用断点一次:
enable once 1
当第一次命中以后,再次调用函数 test_fun
时不会再次被命中,使用 enable once 1
命令后,第一次命中会暂停,后面的调用都不会再次命中。如果此时使用命令 info b
去查看断点信息,会发现 1 号断点的Enb
状态已经变为 n
。
示例代码:
#include <iostream>
#include <string>
void fun_test(int a, const char *str)
{
printf("a is %d, str is %s\n", a, str);
}
int main(int argc, char *argv[])
{
for (int i = 0; i < 10; i++)
{
fun_test(10, "test");
}
}
断点过程:
(gdb) b fun_test
Breakpoint 1 at 0x969: file demo.cpp, line 6.
(gdb) disable 1
(gdb) enable once 1
(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo
ret is 8
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
[Inferior 1 (process 32327) exited normally]
(gdb)
3. 启用断点并删除
这同样是启用断点的一种变化用法,即如果断点被启用,当下次命中该断点后,会自动删除。该功能与临时断点相似,相当于把一个被禁用的断点转换为临时断点。语法如下:
enable delete 断点编号
先为函数 fun_test
设置一个断点,并禁用它,然后再启用并删除它,依次执行的命令如下:
b test_fun
disable 1
enable delete 1
示例代码如下:
#include <iostream>
#include <string>
void fun_test(int a, const char *str)
{
printf("a is %d, str is %s\n", a, str);
}
int add(int a, int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
int ret = add(3, 5);
std::cout << "ret is " << ret << std::endl;
for (int i = 0; i < 10; i++)
{
fun_test(10, "test");
}
}
在 gdb
中输入 r
执行程序,可以发现 fun_test
中的断点被执行一次,然后自动被删除。
(gdb) b fun_test
Breakpoint 1 at 0x969: file demo.cpp, line 6.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) disable 1
(gdb) enable delete 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint del y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo
ret is 8
Temporary breakpoint 1, fun_test (a=10, str=0x555555554b21 "test")
at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
[Inferior 1 (process 8103) exited normally]
(gdb)
4. 启用断点并命中N次
这也是启用断点的一种变化用法,即启用断点后可以命中 N
次,但是命中 N
次后,该断点就会被自动禁用,不会再次命中。语法如下:
enable count 数量 断点编号
如果想重新启用已经禁用的断点,并命中 5 次,那么可以使用以下命令:
enable count 5 1
仍然以 fun_test
函数断点为例。先为 fun_test
设置断点,然后禁用,最后以再次启用并命中 5 次的方式启用该断点。在命中 5 次之后,该断点就会被禁用,如图所示,断点命中了 5 次(可以看到输入了 5 次c)以后自动被禁用,从最后的提示信息也可以看到,1 号断点已经命中了 5 次。
(gdb) b fun_test
Breakpoint 1 at 0x969: file demo.cpp, line 6.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) disable 1
(gdb) enable count 5 1
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint dis y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
disable after next 5 hits
(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo
ret is 8
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
[Inferior 1 (process 8285) exited normally]
(gdb)
5. 忽略断点前N次命中
与条件断点类似,即在设置断点时可以指定接下来的 N
次命中都忽略,直到第 N+1
次命中时运行才暂停。语法如下:
ignore 断点编号 次数
例如我们为函数 fun_test
设置了断点,但是因为 fun_test
可能被多次调用,所以我们希望在第 8 次被调用时能够命中,前 7次的调用都被忽略,则使用以下命令:
ignore 1 7
这样在执行代码时,前 7 次对函数 fun_test
的调用都会被忽略,不会命中断点,但是从第 8 次调用开始都会命中,如下所示:
(gdb) b fun_test
Breakpoint 1 at 0x969: file demo.cpp, line 6.
(gdb) ignore 1 7
Will ignore next 7 crossings of breakpoint 1.
(gdb) r
Starting program: /home/wohu/cppProject/book_debug/chapter_3.1/demo
ret is 8
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
Breakpoint 1, fun_test (a=10, str=0x555555554b21 "test") at demo.cpp:6
6 printf("a is %d, str is %s\n", a, str);
(gdb) c
Continuing.
a is 10, str is test
[Inferior 1 (process 8593) exited normally]
(gdb)
6. 查看断点
查看断点可以通过下列命令实现:
info breakpoints
info break
info b
i b
上述命令只有第一个比较长,后面的 3 个都是简化缩写形式,所有的命令执行结果都是相同的,如下所示。
(gdb) b fun_test
Breakpoint 1 at 0x969: file demo.cpp, line 6.
(gdb) info breakpoint
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
也可以只查看某一个具体的断点,方法为在这些命令后面加上断点编号,
(gdb) info breakpoints 1
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) info breakpoint 1
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) info break 1
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) info b 1
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb) i b 1
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000969 in fun_test(int, char const*) at demo.cpp:6
(gdb)
查看断点信息的命令由 info
和 breakpoint
两个命令组合而成,这两个命令有多种组合方式。
info
可以写为两种形式:info
和i
。breakpoint
可以写为 3 种形式:breakpoint
、break
和b
。
因此,一共有 6 种组合形式,例如, i breakpoint
也是查看断点的有效命令。
7. 删除断点
删除断点主要有两个相关的命令,即 clear
和 delete
。
7.1 删除所有断点
在 gdb
中输入以下命令就会删除所有的断点
delete
在删除之前会有确认对话框,询问是否删除所有断点。如果选择 y
,则删除所有断点,否则不会执行任何操作。
(gdb) b demo.cpp:10
Breakpoint 1 at 0x990: file demo.cpp, line 10.
(gdb) b demo.cpp:12
Breakpoint 2 at 0x998: file demo.cpp, line 12.
(gdb) b demo.cpp:14
Breakpoint 3 at 0x9a9: file demo.cpp, line 14.
(gdb) delete
Delete all breakpoints? (y or n) y
7.2 删除指定断点
delete 断点编号
比如要删除 5 号断点,可以在 gdb
中输入以下命令:
delete 5
如果要同时删除编号为 5 和 6 的两个断点,可以使用以下命令:
delete 5 6
7.3 删除指定范围的断点
delete 范围
如果要删除编号为 5~7 的断点,则可以使用以下命令:
delete 5-7
还可以删除多个范围的断点,比如要删除编号为 5-7
和 10-12
的断点,则可以使用以下命令:
delete 5-7 10-12
7.4 删除指定函数的断点
clear 函数名
比如要删除 test_fun
函数断点,可以执行以下命令:
clear test_fun
这会删除所有的 test_fun
函数断点。如果有多个同名函数断点,这些同名函数断点都会被删除。
7.5 删除指定行号的断点
clear 行号
比如要删除 demo.cpp
第 10 行的断点,可以使用命令:
clear demo.cpp:10
也可以简写为
clear 10
删除断点命令 clear
和 delete
是有区别的。
delete
命令是全局的,不受栈帧的影响;clear
命令受到当前栈帧的制约,删除的是将要执行的下一处指令的断点;delete
命令可以删除所有断点,包括观察点和捕获点等;clear
命令不能删除观察点和捕获点;