编译 Debug 版本

gcc 命令加入 -g 选项,编译 Debug 版本。

BASH

之后就可以使用 GDB 来调试程序了。为 GDB 指定要运行的程序的方法有两种:

BASH

BASH

进入 GDB 交互界面后,使用 file <executable> 指令加载可执行文件:

1
(gdb) file hello

执行程序

使用 run 指令让程序运行直至完成:

1
(gdb) run
提示

在 GDB 环境下也可以进行标准输入输出。

退出 GDB

使用 quit 指令退出 GDB 交互界面:

1
(gdb) quit

传入参数

考虑下面这个 echo 程序:

echo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// echo.c
#include <stdio.h>
#include <stdlib.h>

void usage() {
printf("usage: echo <string>\n");
exit(-1);
}

int main(int argc, char *argv[]) {
if (argc != 2) {
usage();
}

printf("%s\n", argv[1]);
return 0;
}

编译 Debug 版本:

BASH

这个 echo 可执行文件需要传入一个参数,我们仍然有两种方法:

  • 在命令行中传入参数:

BASH
注意

--agrs 选项包含了 ./echo 这条指令,它将作为一个参数传递给可执行文件,因此必须用 ./echo 而不是 echo

  • 在 GDB 交互界面传入参数:

1
2
(gdb) file echo
(gdb) set args 'hello, world'

提示

set args [arg1] ...run 两条指令可以合并为 run [arg1] ...

追踪程序运行

以这个斐波那契数列计算程序为例:

fibo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// fibo.c
#include <assert.h>
#include <stdio.h>

int fibo(int n) {
assert(n > 0);
if (n <= 2) {
return 1;
} else {
return fibo(n - 1) + fibo(n - 2);
}
}

int main(int argc, char *argv[]) {
int n = 10;
int fibo_n = fibo(n);
printf("fibo(%d) = %d\n", n, fibo_n);

return 0;
}

开始/重启 start

先进入 GDB 交互界面,这次不用 run 来运行,而用 start

1
(gdb) start

start 指令会让程序开始运行并停在 main 函数的起始处。观察到(应当类似如下内容):

1
2
Temporary breakpoint 1, main (argc=1, argv=0x7ffeb3641978) at fibo.c:15
15 int n = 10;

表明即将执行第 15 行代码。

注意

在程序运行中使用 start 会让程序重启。

步入 step

要一步一步执行程序,使用步入 step

1
2
3
(gdb) step
16 int fibo_n = fibo(n);
(gdb)

接下来如果想要继续步入,输入 即可。

步出 finish

继续步入,直到进入 fibo(9) 函数体:

1
2
fibo (n=9) at fibo.c:6
6 assert(n > 0);

如果继续步入下去,还会看到 fibo(8) fibo(7) 等等的执行过程,实在太浪费时间了!我们需要一个从函数内部跳出的指令:步出 finish

1
2
3
4
5
(gdb) finish
Run till exit from #0 fibo (n=9) at fibo.c:6
0x000055cc3e21b1c1 in fibo (n=10) at fibo.c:10
10 return fibo(n - 1) + fibo(n - 2);
Value returned is $1 = 34

我们跳过了 fibo(9) 的运算,并得到了结果。

步过 next

如果我们继续步入,就会开始执行 fibo(8),这样又要步出一次,太麻烦了!我们需要一个跳过这一行所有函数的指令:步过 next

1
2
3
(gdb) next
12 }
(gdb)

这个神秘的右括号表示的是函数最后一条指令执行后函数返回前的时刻。
之后我们可以再用一次步过或步入就能离开 fibo(10) 这个函数。

1
2
main (argc=1, argv=0x7ffeb3641978) at fibo.c:17
17 printf("fibo(%d) = %d\n", n, fibo_n);

继续 continue

剩下的就是输出结果了,我们已经不关心了,可以用继续 continue 来让程序继续运行直至退出。

停止 kill

杀死进程。

1
2
3
(gdb) kill
Kill the program being debugged? (y or n) y
[Inferior 1 (process 108565) killed]

断点调试

在 GDB 中查看源代码

使用 list 指令查看源代码,共有五种:

1
2
3
4
5
list
list <line number>
list <file>:<line number>
list <function name>
list <file>:<function name>

设置断点

使用 break 指令设置断点,与 list 一样有五种,比如对第 10 行设置断点可以写为:

1
2
(gdb) break 10
Breakpoint 1 at 0x119d: file echo.c, line 11.

删除/禁用断点

首先用 info breakpoints 查看所有断点信息。各列信息分别是编号Num类型Type是否为临时断点Disp是否启用Enb位置Address当前状态What
记住断点的编号,然后使用 disable breakpoints [num] 来禁用之。

如果不再需要这个断点,使用 delete breakpoints [num] 删除之。

临时断点

临时断点只会中断一次。start 相当于在 main 函数处设置了一个临时断点。

使用 tbreak 来创建临时断点。

后记

事实上 GDB 还有条件断点、观察点等等厉害的工具,但考虑到使用命令行进行这些操作实在太费事了,就只写到这里。


本站由 Samustach Floresein 使用 Stellar 1.33.1 主题创建。
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
本站总访问量 次。

载入天数…载入时分秒…

Static Badge
Static Badge