GDB 简单使用
1. 案例代码
#include<stdio.h>
int main(void)
{
int x;
printf("Hello World!\n");
if(x=1)
{
printf("Now x is %d\n",x);
x++;
printf("Now x is %d\n",x);
x++;
printf("Now x is %d\n",x);
}
return 0;
}
2. 编译并输出可执行文件
添加参数-o指定输出文件名
# cpp
g++ main.cpp -o main
# c
gcc main.c -o main
编译结果:
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0gcc main.c -o main
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0
3. 警告与调试参数
添加参数-g来开启调试
# cpp
g++ main.cpp -g -Wall -Werror -o main
# c
gcc main.c -g -Wall -Werror -o main
其中-Wall是开启所有警告
In order to compile with all warnings enabled and to produce ANSI C compatible code, I recommend using the flags
-Wall -ansi详见这里
编译结果:
1. 只添加 -Wall
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0$ gcc main.c -g -Wall -o main
main.c: In function ‘main’:
main.c:7:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
7 | if(x=1)
| ^
2. 添加 -Wall -Werror
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0$ gcc main.c -g -Wall -Werror -o main
main.c: In function ‘main’:
main.c:7:5: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
7 | if(x=1)
| ^
cc1: all warnings being treated as errors
- 对比可以明显看出,添加 -Werror 后,编译失败
-
此外可以看出,添加 -g 后,生成的可执行文件比不添加 -g 大
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0gcc main.c -g -o main_g
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0 gcc main.c -o main_o
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0$ ls -all
总用量 72
drwxrwxr-x 2 keruone keruone 4096 2月 5 16:37 .
drwxrwxr-x 3 keruone keruone 4096 1月 24 17:11 ..
-rwxrwxr-x 1 keruone keruone 16696 2月 5 16:36 main
-rw-rw-r-- 1 keruone keruone 127 2月 5 16:28 main.c
-rwxrwxr-x 1 keruone keruone 19216 2月 5 16:37 main_g
-rwxrwxr-x 1 keruone keruone 16696 2月 5 16:37 main_o
4. GDB基础
1. 启动GDB
gdb <executable name>
比如:
gdb main
注意,对于gcc编译时,需要添加参数-g
– 添加参数-g后的gdb结果
详细输出
```bash
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0$ gdb main_g
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.2) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main_g...
(gdb)
```
</details>
- 不添加参数
-g后的gdb结果
详细输出
keruone@Ubuntu20:~/xuehao/CS-Basics_Notes/PA/PA0$ gdb main_o GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.2) 9.2 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from main_o... (No debugging symbols found in main_o) (gdb)
可以发现,不添加参数-g时,gdb无法读取符号信息,无法进行调试
2. break 添加断点
以上文的main_g为例,在进入gdb后,添加断点
# 添加断点
(gdb) break <line number>
此时,如果顺利应该会输出:
(gdb) break 7
Breakpoint 1 at 0x1161: file main.c, line 7.
可以看到,断点已经添加成功,断点编号为1,断点位置为0x1161,文件为main.c,行号为7
3. run 运行程序
# 运行程序
(gdb) run
此时,如果顺利应该会输出:
(gdb) run
Starting program: /home/keruone/xuehao/CS-Basics_Notes/PA/PA0/main_g
Hello World!
Breakpoint 1, main () at main.c:7
7 if(x=1)
可以看到,程序已经运行到断点处,程序停在了第7行
4. step 和 next 单步执行
step和next都是单步执行,区别在于step会进入函数内部,next不会进入函数内部
5. continue 继续执行
continue是继续执行,直到下一个断点
6. print 和 set 查看&修改变量值
使用print命令查看变量值
# 查看变量值
(gdb) print <var name to print>
此时,如果顺利应该会输出:
(gdb) print x
$1 = 1
可以看到,变量x的值为0
$后面的数字是历史值的编号
– GDB 会为每个 print 命令的输出结果分配一个唯一的编号
– 编号从 1 开始递增
– 这些编号前面加上 $ 符号
注意,你也可以在此处直接使用set修改变量的值
这个值会影响程序接下来的运行!
(gdb) set x=4
(gdb) print x
$2 = 4
这里编号增加的原因如上述
set影响输出示例
(gdb) run
Starting program: /home/keruone/xuehao/CS-Basics_Notes/PA/PA0/main_g
Hello World!
Breakpoint 1, main () at main.c:7
7 if(x=1)
(gdb) print x
1 = 0
(gdb) next
9 printf("Now x is %d\n",x);
(gdb) next
Now x is 1
10 x++;
(gdb) print x2 = 1
(gdb) set x = 4
(gdb) print x
$3 = 4
(gdb) next
11 printf("Now x is %d\n",x);
(gdb) next
Now x is 5
12 x++;
(gdb)
7. watch 监视变量值的变化
使用watch命令监视变量值的变化
(gdb) run
Starting program: /home/keruone/xuehao/CS-Basics_Notes/PA/PA0/main_g
Hello World!
Breakpoint 1, main () at main.c:7
7 if(x=1)
(gdb) watch x
Hardware watchpoint 4: x
(gdb) continue
Continuing.
Hardware watchpoint 4: x
Old value = 0
New value = 1
main () at main.c:9
9 printf("Now x is %d\n",x);
(gdb) continue
Continuing.
Now x is 1
Hardware watchpoint 4: x
Old value = 1
New value = 2
main () at main.c:11
11 printf("Now x is %d\n",x);
(gdb) continue
Continuing.
Now x is 2
Hardware watchpoint 4: x
Old value = 2
New value = 3
main () at main.c:13
13 printf("Now x is %d\n",x);
(gdb) continue
Continuing.
Now x is 3
Watchpoint 4 deleted because the program has left the block in
which its expression is valid.
__libc_start_main (main=0x555555555169 <main>, argc=1, argv=0x7fffffffdf18, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffdf08) at ../csu/libc-start.c:342
342 ../csu/libc-start.c: 没有那个文件或目录.
(gdb)
- 可以看到,当变量x的值发生变化时,程序会停止运行,并输出变量x原来的值和新的值
- 当程序运行结束时,监视点会自动删除
8. list 查看代码
使用list命令查看当前代码前后共10行代码
(gdb) list
2
3 int main(void)
4 {
5 int x;
6 printf("Hello World!\n");
7 if(x=1)
8 {
9 printf("Now x is %d\n",x);
10 x++;
11 printf("Now x is %d\n",x);
(gdb)
9. kill 和 quit 终止程序和退出GDB
使用kill命令终止程序
使用quit命令退出GDB
5. 快捷键
绝大多数命令都可以使用第一个字母作为快捷键
| 命令 | 快捷键 |
|---|---|
| break | b |
| run | r |
| step | s |
| next | n |
| continue | c |
| p | |
| set | set |
| watch | watch |
6. 结语
这里就引用参考网页的结语了
你现在已经了解了足够的GDB来尝试自己的程序。这里有一些重要的主题没有被触及,以保持简单,例如处理分段错误和其他类型的崩溃或使用工具如 Valgrind 去寻找内存泄漏。
记住,GDB 自带了一个优秀的帮助系统。在 (gdb) 提示下,只需键入 help 即可获得选项。有关特定命令的详细信息,请使用以下语法:
help <command>
另一个重要的要点是使用快捷键(例如 ‘q’ 表示 ‘quit’)。GDB 让你在不引起歧义的情况下使用快捷键。
在学习了 GDB 之后,你不需要恐慌下一次你的程序崩溃了。你现在有了一把非常好的武器。