什么是GDB
GDB是GNU开源组织发布的一个强大的Linux下的程序调试工具。
一般来说,GDB主要帮助你完成下面四个方面的功能:
-
启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
-
可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
-
当程序被停住时,可以检查此时你的程序中所发生的事。
-
动态的改变你程序的执行环境。
GDB调试的对象
GDB主要来调试C/C++语言写的程序,当然也就可以调试其他语言程序。GDB调试一定要是可执行文件而不是.c文件。
要用gcc进行编译,具体的命令如下:
gcc -g 源文件.c -o 输出的目标文件
-g,-o参数缺一不可。
GDB常用的调试命令
- 启动
使用命令gdb 程序名
启动,启动成功的标志就是最终输出的 (gdb)。
[root@bogon demo]# gdb main.exe
GNU gdb (GDB) 8.0.1
Copyright (C) 2017 Free Software Foundation, Inc.
......
(gdb)
- GDB常用的调试指令
调试指令 | 作 用 |
---|---|
(gdb) break xxx;(gdb) b xxx | 在源代码指定的某一行设置断点,其中 xxx 用于指定具体打断点的位置。 |
(gdb) run;(gdb) r | 执行被调试的程序,其会自动在第一个断点处暂停执行。 |
(gdb) continue;(gdb) c | 当程序在某一断点处停止运行后,使用该指令可以继续执行,直至遇到下一个断点或者程序结束。 |
(gdb) next;(gdb) n | 令程序一行代码一行代码的执行(逐过程,函数直接执行)。 |
(gdb)step;(gdb)s | 单步调试(逐语句:跳入自定义函数内部执行) |
(gdb)backtrace;(gdb)bt | 查看函数的调用的栈帧和层级关系 |
(gdb) print xxx;(gdb) p xxx | 打印指定变量的值,其中 xxx 指的就是某一变量名。 |
(gdb)info breakpoints | 查看当前设置的所有断点 |
(gdb)delete breakpoints num | 删除第num个断点 |
(gdb)display | 追踪查看具体变量值 |
(gdb)undisplay | 取消追踪观察变量 |
(gdb)watch | 被设置观察点的变量发生修改时,打印显示 |
(gdb)i watch | 显示观察点 |
(gdb) list;(gdb) l | 显示源程序代码的内容,包括各行代码所在的行号。 |
(gdb) quit;(gdb) q | 终止调试。 |
(gdb) run argv[1] argv[2] | 调试时命令行传参 |
实例:
(gdb) l <-- 显示带行号的源代码
1 #include <stdio.h>
2 int main ()
3 {
4 unsigned long long int n, sum;
5 n = 1;
6 sum = 0;
7 while (n <= 100)
8 {
9 sum = sum + n;
10 n = n + 1;
(gdb) <-- 默认情况下,l 选项只显示 10 行源代码,如果查看后续代码,安装 Enter 回车即可
11 }
12 return 0;
13 }
(gdb) b 7 <-- 在第 7 行源代码处打断点
Breakpoint 1 at 0x400504: file main.c, line 7.
(gdb) r <-- 运行程序,遇到断点停止
Starting program: /home/mozhiyan/demo1/main.exe
Breakpoint 1, main () at main.c:7
7 while (n <= 100)
Missing separate debuginfos, use: debuginfo-install glibc-2.17-55.el7.x86_64
(gdb) p n <-- 查看代码中变量 n 的值
$1 = 1 <-- 当前 n 的值为 1,$1 表示该变量所在存储区的名称
(gdb) b 12 <-- 在程序第 12 行处打断点
Breakpoint 2 at 0x40051a: file main.c, line 12.
(gdb) c <-- 继续执行程序
Continuing.
Breakpoint 2, main () at main.c:12
12 return 0;
(gdb) p n <-- 查看当前 n 变量的值
$2 = 101 <-- 当前 n 的值为 101
(gdb) q <-- 退出调试
A debugging session is active.
Inferior 1 [process 3080] will be killed.
Quit anyway? (y or n) y <-- 确实是否退出调试,y 为退出,n 为不退出
[root@bogon demo]#
注:
监视点
大型软件或大量使用指针的程序中,很难弄清变量在什么地方被改变,要想找到变量在何处被改变,可以使用 watch 命令(监视点,watchpoint)。格式如下:
watch <表达式>
:表达式发生变化时暂停运行。
awatch <表达式>
:表达式被访问、改变时暂停运行。
rwatch <表达式>
:表达式被访问时暂停运行。
需要注意,设置监视点可能会降低运行速度。
改变变量的值
格式:set variable <变量=表达式>
。例如命令 set variable options = 0,将变量 options 的值改成了 0。
内核转储
内核转储(core dump)的最大好处是,它能保存问题发生时的状态。只要有问题发生时程序的可执行文件和内核转储,就可以知道进程当前的状态。
大多数 Linux 发行版默认关闭了内核转储功能,使用 ulimit 命令可以查看当前的内核转储功能是否有效。
$ ulimit -c
0
-c 选项表示内核转储文件的大小限制,0 表示内核转储无效。开启内核转储执行命令:
$ ulimit -c unlimited
or
$ ulimit -c 上限
unlimited 意思是不限制内核转储文件的大小,发生问题时进程的内存就可以全部转储到内核转储文件中。或者设置内核转储文件的上限,在参数中指定上限大小,单位为 Kb。
程序发生异常时会在当前目录下生成内核转储文件。例如程序 a.out 生成转储文件 core,使用以下方式启动 GDB:
$ gdb -c core ./a.out
参考:
http://c.biancheng.net/view/8255.html
https://blog.csdn.net/horotororensu/article/details/82256832
https://blog.csdn.net/awm_kar98/article/details/82840811