gdb 是 linux 下非常好用的一个调试工具, 虽然它是命令行模式的调试工具, 但是它的功能强大到你无法想象, 这里简单介绍下 gdb 下常用的命令.
首先编译生成可执行文件(这里的 test.c 是一个简单的求前 n 项和的程序).
gcc -g test.c -o test(-g 选项告诉 gcc 在编译程序时加入调试信息).
接下来可以这样.
gdb test
然后你就会看到出现好多信息在屏幕上, 大致说的是 gdb 的一些版本信息说明之类的, 但是它对你调试程序没用呀, 所以, 你可以加上 - q 选项, 不输出它们.
- gdb -q test
- wang@king:~$ gdb -q test
Reading symbols from test...done.
(gdb)
有没有觉得这个世界一下子清净了许多.
也可以先进入 gdb 模式, 然后再加载文件.
- wang@king:~$ gdb -q
- (gdb) file test
Reading symbols from test...done.
(gdb)
好了, 现在开始调试了, 但是我还想看看我的代码怎么办, gdb 提供了一条命令, 可以让你的程序显示出来.
- (gdb) //list 默认一次显示 10 行
- 1 #include<stdio.h>
- 2 int func(int n)
- 3 {
- 4 int i;
- 5 int sum=0;
- 6 for(i=0;i<n;i++)
- 7 {
- 8 sum+=i;
- 9 }
- 10 return sum;
- (gdb) // 直接输入回车重复上次命令, 显示接下来的 10 行
- 11 }
- 12 int main()
- 13 {
- 14 int n;
- 15 printf("请输入 n 的值");
- 16 scanf("%d",&n);
- 17 printf("1+2+..+%d=%d",n,func(n));
- 18 return 0;
- 19 }
- (gdb)
list 默认参数可以用 show listsize 来查看, 如果感觉 10 行太多或者太少, 还可以用 set listsize <count > 来更改.
list 还可以加上其他参数, 比如:
list 5,10 显示第 5 行到第 10 行的代码;
list func 显示 func 函数周围的代码, 显示范围和 list 参数有关;
list test.c:5,10 显示源文件 test.c 第 5 行到第 10 行的代码, 一般用于调试含多个源文件的程序.
gdb 还支持字符串查找, search str, 从当前行开始, 向前查找含 str 的字符串;
reverse-search str, 从当前行开始, 向后查找含 str 的字符串.
现在你的屏幕应该被占满了吧? 想清空屏幕, 可是还在 gdb 里面呀, 怎么办? 其实, gdb 也支持运行 linux 命令的, 可以在 gdb 的提示符中, 输入 shell, 然后在输入你需要的命令就可以了
(gdb) shell clear
这样也能达到清屏的效果.
看了程序的代码, 感觉第 6 行代码可能有点问题, 现在就需要我就需要设置一个断点, 让程序停在第 6 行之前.
(gdb) break 6
Breakpoint 1 at 0x80484c8: file test.c, line 6.
(gdb)
下面一行的 信息, 1 说明我设置的这个断点是第一个断点, 断点所在内存地址为 0x80484c8, 它在文件 test.c 的第 6 行.
gdb 还可以以条件表达式设置断点.
(gdb) break 7 if n==6
Breakpoint 2 at 0x80484d1: file test.c, line 7.
(gdb)
这个断点的含义是, 如果 n 的值为 6, 则程序运行到第 7 行停止.
当然, 还可以直接在某个函数处设置断点; 直接 break 函数名就可以了,
然后我们想看下设置的断点信息, 可以使用 info breakpoints 命令.
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484c8 in func at test.c:6
2 breakpoint keep y 0x080484d1 in func at test.c:7
stop only if n==6
4 breakpoint keep y 0x080484c1 in func at test.c:5
(gdb)
Num 表示断点的编号; Type 表示断点的断点的类型, 第二个断点类型还加上了条件; Disp 表示中断点在执行一次之后是否失去作用, dis 为是, keep 为不是; Enb 表示当前中断点是否有效, y 为是, n 为否; Address 表示中断点所处的内存地址; What 指出断点所处的位置.
如果不需要程序在该断点暂停时, 有两种方法, 一种是使该断点失效, 一种是直接删除该断点.
- (gdb) disable 1
- (gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep n 0x080484c8 in func at test.c:6
2 breakpoint keep y 0x080484d1 in func at test.c:7
stop only if n==6
3 breakpoint keep y 0x080484c1 in func at test.c:5
(gdb)
可以看到, 第一个断点的 Enb 变为 n 了, 表示该断点已经无效了, 如果需要恢复, 可以使用 enable 命令. 这里需要注意的是, disable 后面的参数为断点的编号. 而不是行号.
直接删除该断点, 可以使用 clear 命令和 delete 命令.
(gdb) clear 6
已删除的断点 1
(gdb)
clear 命令后面的参数为设置断点的行号, clear 后面参数还可以加设置断点的函数名.
delete 命令后面的参数为断点的编号; 可以一次删除多个断点, 断点编号之间用空格隔开; 如果 delete 后没有参数, 默认删除所以断点, 会给出提示选择是否操作.
(gdb) delete
删除所有断点吗? (y or n)
断点设置好了, 现在就可以调试了,
- (gdb) run // 开始执行程序
- Starting program: /home/wang/test
请输入 n 的值 10
- Breakpoint 1, func (n=10) at test.c:6 // 设置的第一个断点, 程序在第 6 行暂停
- 6 for(i=0;i<n;i++)
- (gdb) continue // 让程序继续运行, 直到下个断点或者结束
Continuing.
- Breakpoint 2, func (n=10) at test.c:8 // 第二个断点设置的是 i==6 时停止
- 8 sum+=i;
- (gdb) print i // 用 print 命令打印出 i 的值
- $1 = 6
- (gdb) print sum
- $2 = 15
- (gdb) next // 继续执行下一条语句, 只执行一条.
- 6 for(i=0;i<n;i++)
- (gdb) next
- 8 sum+=i;
- (gdb) print i
- $3 = 7
- (gdb) continue
Continuing.
- 1+2+..+10=45[Inferior 1 (process 23636) exited normally]
- (gdb) quit // 退出 gdb 调试
上面出现了很多命令, 下面就来说说都是怎么用的.
run, 开始运行程序;
continue, 程序暂停时继续运行程序的命令;
print 变量名或表达式, 打印该变量或者该表达式的值. whatis 变量名或者表达式, 可以显示该变量或表达式的数据类型.
print 变量 = 值, 这种形式还可以给对应的变量赋值; 类似的还有 set variable 变量 = 值. 作用和用 print 赋值相同.
next, 继续执行下一条语句; 还有一条命令 step, 与之类似, 不同的是, 当下一条语句遇到函数调用的时候, next 不会跟踪进入函数, 而是继续执行下面的语句, 而 step 命令则会跟踪进入函数内部.
- (gdb) run
- Starting program: /home/wang/test
- Breakpoint 1, main () at test.c:16
- 16 scanf("%d",&n);
- (gdb) next
请输入 n 的值 10
- 17 printf("1+2+..+%d=%d",n,func(n));
- (gdb) next //next 命令直接执行下一行, 没有进入 func 函数
- 18 return 0;
- (gdb)
- (gdb) run
- Starting program: /home/wang/test
- Breakpoint 1, main () at test.c:16
- 16 scanf("%d",&n);
- (gdb) n
请输入 n 的值 10
- 17 printf("1+2+..+%d=%d",n,func(n));
- (gdb) step //step 命令跟踪进入了 func 函数
- func (n=10) at test.c:5
- 5 int sum=0;
- (gdb)
还有 nexti 和 stepi 命令, 这两个是单步执行一条机器指令, 比如 (i=0;i<n;i++) 这条语句需要输入多个 nexti 才能执行完; 两个的区别和上面相同.
quit, 退出 gdb 调试, 如果调试中想要退出, 可以直接输入该命令, 会出现提示选择是否退出. kill 命令, 结束当前程序的调试,(不会退出 gdb).
(gdb) quit
A debugging session is active.
Inferior 1 [process 32229] will be killed.
Quit anyway? (y or n)
来源: http://www.bubuko.com/infodetail-2646369.html