Linux基础知识(14)- GDB 调试器(二)| 普通断点、单步调试和查看变量
在 “Linux基础知识(13)- GDB 调试器(一)| 安装配置和基本使用方法” 里我们完成了 GDB 的安装配置,并演示了 GDB 几个内部命令的基本使用方法,本文将演示普通断点、单步调试和查看变量。
1. 创建 C 程序
1) 代码如下
$ cd ~/
$ vim test2.c
#include <stdio.h>
int testFunc() {
for (int i=0; i<3; i++ ) {
printf("printf i=%d\n", i);
}
}
int main(int argc, char* argv[]) {
if (argv[1] == NULL) {
printf("Hello world - GDB\n");
} else {
printf("Hello world - %s\n", argv[1]);
}
testFunc();
}
2)编译并设置调试信息
$ gcc -g test2.c -o test2
$ ./test2
Hello world - GDB
printf i=0
printf i=1
printf i=2
$ ./test2 "Message"
Hello world - Message
printf i=0
printf i=1
printf i=2
2. 设置普通断点
1) 使用 break 命令设置断点
使用 GDB 启动 test2 程序:
$ gdb -q test2
Reading symbols from test...
(gdb) l
1 #include <stdio.h>
2
3 int testFunc() {
4 for (int i=0; i<3; i++ ) {
5 printf("printf i=%d\n", i);
6 }
7 }
8
9 int main(int argc, char* argv[]) {
10
(gdb)
11 if (argv[1] == NULL) {
12 printf("Hello world - GDB\n");
13 } else {
14 printf("Hello world - %s\n", argv[1]);
15 }
16
17 testFunc();
18 }
19
运行 break (简写 b) 命令在指定行设置断点,使用方法是 b 空格 行号。
(gdb) b 11
Breakpoint 1 at 0x11b4: file test2.c, line 11.
(gdb) b 17
Breakpoint 2 at 0x11f1: file test2.c, line 17.
查看断点信息:
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000000011b4 in main at test2.c:11
2 breakpoint keep y 0x00000000000011f1 in main at test2.c:17
说明:
NUM: 断点编号
Disp:断点执行一次之后是否还有效(keep: 有效,dis: 无效)
Enb: 当前断点是否有效(y: 有效,n: 无效)
Address:内存地址
(gdb) q
2) 使用 tbreak 命令设置断点
使用 tbreak 命令设置的断点,仅会作用 1 次,程序暂停之后,该断点就会自动消失。
使用 GDB 启动 test2 程序:
$ gdb -q test2
Reading symbols from test...
(gdb)
运行 tbreak 命令在指定行设置断点,使用方法是 tbreak 空格 行号。
(gdb) tbreak 11
Temporary breakpoint 1 at 0x11b4: file test2.c, line 11.
(gdb) tbreak 17
Temporary breakpoint 2 at 0x11f1: file test2.c, line 17.
(gdb) r
Starting program: /home/xxx/test2
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe228) at test2.c:11
11 if (argv[1] == NULL) {
(gdb) c
Continuing.
Hello world - GDB
Temporary breakpoint 2, main (argc=1, argv=0x7fffffffe228) at test2.c:17
17 testFunc();
(gdb) c
Continuing.
printf i=0
printf i=1
printf i=2
[Inferior 1 (process 12928) exited normally]
(gdb) info b
No breakpoints or watchpoints.
(gdb) q
3) 使用 rbreak 命令设置断点
rbreak 命令的作用对象是 C、C++ 程序中的函数,它会在指定函数的开头位置打断点。
语法格式:
(gdb) rbreak regex
regex 为一个正则表达式,程序中函数名只要满足 regex 条件,rbreak 命令就会在其内部的开头位置打断点。值得一提的是,rbreak 命令打的断点和 break 命令打断点的效果是一样的,会一直存在,不会自动消失。
使用 GDB 启动 test2 程序:
$ gdb -q test2
Reading symbols from test...
(gdb)
运行 rbreak 命令在指定行设置断点,使用方法是 tbreak 空格 regex。
(gdb) rbreak testFunc
Breakpoint 1 at 0x1169: file test2.c, line 3.
int testFunc();
(gdb) r
Starting program: /home/xxx/test2
Hello world - GDB
Breakpoint 1, testFunc () at test2.c:3
3 int testFunc() {
...
(gdb) q
4) 清除断点
运行 clear 命令删除某一行对应的断点,使用方法是 clear 空格 行号。
(gdb) clear 11
(gdb) clear 17
(gdb) info b
Deleted breakpoint 2 No breakpoints or watchpoints.
3. 单步调试
使用 GDB 启动 test2 程序,设置断点并运行到断点:
$ gdb -q test2
Reading symbols from test...
(gdb) b 11
Breakpoint 1 at 0x11b4: file test2.c, line 11.
(gdb) b 17
Breakpoint 2 at 0x11f1: file test2.c, line 17.
(gdb) r
Starting program: /home/xxx/test2
Breakpoint 1, main (argc=1, argv=0x7fffffffe228) at test2.c:11
11 if (argv[1] == NULL) {
1) step 命令
运行 step (简写 s) 命令单步执行,进入 testFunc() 函数:
(gdb) c
Continuing.
Hello world - GDB
Breakpoint 2, main (argc=1, argv=0x7fffffffe228) at test2.c:17
17 testFunc();
(gdb) s
testFunc () at test2.c:3
3 int testFunc() {
(gdb) s
4 for (int i=0; i<3; i++ ) {
(gdb) c
Continuing.
printf i=0
printf i=1
printf i=2
[Inferior 1 (process 12944) exited normally]
(gdb) q
2) next 命令
运行 next (简写 n) 命令单步执行,跳过 testFunc() 函数:
(gdb) c
Continuing.
Hello world - GDB
Breakpoint 2, main (argc=1, argv=0x7fffffffe228) at test2.c:17
17 testFunc();
(gdb) n
printf i=0
printf i=1
printf i=2
18 }
(gdb) c
Continuing.
[Inferior 1 (process 12950) exited normally]
(gdb) q
3)until 命令
运行 until (简写 u) 命令:
(gdb) u
12 printf("Hello world - GDB\n");
(gdb) u 17
Hello world - GDB
Breakpoint 2, main (argc=1, argv=0x7fffffffe228) at test2.c:17
17 testFunc();
注:不带参数的 until 命令,可以使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止。until 命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until 命令才会发生此作用;反之,until 命令和 next 命令的功能一样,只是单步执行程序。
4. 查看变量
使用 GDB 启动 test2 程序:
$ gdb -q test2
Reading symbols from test...
(gdb)
设置断点和运行:
(gdb) b 11
Breakpoint 1 at 0x11b4: file test2.c, line 11.
(gdb) r "message"
Starting program: /home/xxx/test2 "message"
Breakpoint 1, main (argc=2, argv=0x7fffffffe228) at test2.c:11
11 if (argv[1] == NULL) {
运行 print (简写 p) 命令变量的值,使用方法是 p 空格 变量:
(gdb) p argv[1]
$1 = 0x7fffffffe509 "message"
运行 display 命令查看变量或表达式的值,使用方法是 display 空格 变量 (或 display/fmt 空格 变量):
(gdb) display argv[1]
1: argv[1] = 0x7fffffffe509 "message"
(gdb) display/t argv[1]
2: /t argv[1] = 11111111111111111111111111111111110010100001001
(gdb) c
Continuing.
Hello world - message
printf i=0
printf i=1
printf i=2
[Inferior 1 (process 12982) exited normally]
(gdb) r "message2"
Starting program: /home/xxx/test2 "message2"
Breakpoint 1, main (argc=2, argv=0x7fffffffe228) at test2.c:11
11 if (argv[1] == NULL) {
1: argv[1] = 0x7fffffffe508 "message2"
2: /t argv[1] = 11111111111111111111111111111111110010100001000
注:使用 display 命令查看的目标变量或表达式,不仅在执行该命令的同时会看到目标变量的值,后续每次程序停止执行时,GDB 调试器都会将目标变量的值打印出来。
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y argv[1]
2: y /t argv[1]
注:使用 display 命令查看的目标变量或表达式,都会被记录在一张列表(称为自动显示列表)中,通过执行 info dispaly 命令,可以打印出这张表。列表各列的含义:
(1) Num 列,为各变量或表达式的编号,GDB 调试器为每个变量或表达式都分配有唯一的编号;
(2) Enb 列,表示当前各个变量(表达式)是处于激活状态还是禁用状态,如果处于激活状态(用 y 表示),则每次程序停止执行,该变量的值都会被打印出来;反之,如果处于禁用状态(用 n 表示),则该变量(表达式)的值不会被打印;
(3) Expression 列,表示查看的变量或表达式;
(gdb) disable display 2
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y argv[1]
2: n /t argv[1]
注:可以看到,编号为 2 的 argv[1] 变量的 Enb 由 y 变成了 n。处于禁用状态的变量或表达式,程序停止执行时将不再自动打印出它们的值。
(gdb) enable display 2
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y argv[1]
2: y /t argv[1]
注:参数 2 表示要激活的变量或表达式的编号,编号的个数可以是多个,表示一次性激活多个变量或表达式。
参数 fmt 用于指定输出变量或表达式的格式,下表时常用的一些 fmt 参数。
| /fmt | 描述 |
| /x | 以十六进制的形式打印出整数 |
| /d | 以有符号、十进制的形式打印出整数 |
| /u | 以无符号、十进制的形式打印出整数 |
| /o | 以八进制的形式打印出整数 |
| /t | 以二进制的形式打印出整数 |
| /f | 以浮点数的形式打印变量或表达式的值 |
| /c | 以字符形式打印变量或表达式的值 |
注:display 命令和 /fmt 之间不要留有空格。以 /x 为例,应写为 (gdb) display/x expr。
浙公网安备 33010602011771号