GDB调试
概念
-
GDB是由 GNU 软件系统社区提供的调试工具,同GCC配套组成了一套完整的开发环境,GDB是 Linux 和许多类 Unix 系统中的标准开发环境 -
一般来说,
GDB主要帮助你完成下面四个方面的功能- 启动程序,可以按照自定义的要求随心所欲的运行程序
- 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式)
- 当程序被停住时,可以检查此时程序中所发生的事
- 可以改变程序,将一个 BUG 产生的影响修正从而测试其他 BUG
-
在GDB(GNU Debugger)中,命令的缩写是为了提高用户的效率和便捷性而设计的。GDB允许用户使用命令的前几个字符作为缩写,只要这些缩写是唯一的并且不与其他命令冲突。这种设计使得用户在调试过程中可以更快速地输入命令,提高工作效率。
-
命令缩写的规则:
- GDB命令可以被缩写为其前几个字符,只要这些字符足以唯一地标识该命令。
- 例如,
list命令可以缩写为l或li,因为在GDB中没有其他命令以l或li开头。
-
命令示例:
list命令用于显示源代码,可以缩写为l或li。info break命令用于显示断点信息,可以缩写为i b。
-
具体例子:
-
list 命令:
- 完整命令:
list - 缩写形式:
l或li - 解释:在GDB中,没有其他命令以
l或li开头,因此l和li都可以唯一地标识list命令。
- 完整命令:
-
info break 命令:
- 完整命令:
info break - 缩写形式:
i b - 解释:
info命令有很多子命令,但break子命令可以缩写为b,因此info break可以缩写为i b。
- 完整命令:
-
-
准备工作
-
安装gdb
- sudo apt update
- sudo apt install gdb
-
安装后查看gdb是否安装成功
- gdb -v

- gdb -v
-
使用以下命令编译:
gcc -g -Wall program.c -o program

- 通常,在为调试而编译时,我们会关掉编译器的优化选项(
-O), 并打开调试选项(-g)。另外,-Wall在尽量不影响程序行为的情况下选项打开所有warning,也可以发现许多问题,避免一些不必要的 BUG -g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件
- 通常,在为调试而编译时,我们会关掉编译器的优化选项(
-
注:当在
gdb中直接使用回车时,会默认执行上一条命令
常用命令
说明
- program1.c:源文件如下
点击查看代码
#include <stdio.h>
int sum(int a,int b);
int main(int argc, char *argv[])
{
for(int i = 0; i < argc; i++){
printf("argv[%d]: %s\n", i, argv[i]);
}
printf("Hello world\n");
for(int i = 1; i < 5; i++){
printf("%d\n", i);
}
int a = 1, b = 2;
printf("a+b = %d\n", sum(a,b));
return 0;
}
int sum(int a, int b){
return a+b;
}
- program2.c:源文件如下
点击查看代码
int main()
{
pid_t pid = fork();
if(pid > 0){
for(int i = 0; i < 5; i++){
printf("I am parent process, pid = %d\n", getpid());
sleep(1);
}
}else if(pid == 0){
for(int i = 0; i < 5; i++){
printf("I am child process, pid = %d\n", getpid());
sleep(1);
}
}else{
perror("fork() failed");
exit(1);
}
return 0;
}
启动与退出
-
启动:
gdb 可执行程序或者gdbfile [filename]- 方法一

- 方法二

- 方法一
-
退出:
quit/q

给程序设置参数/获取设置参数
-
设置参数:
set args 10 20或者gdb --args program1 10 20- 方法一

- 方法二

- 方法一
-
获取设置参数:
show args

GDB使用帮助
help

查看当前文件代码
-
默认位置显示,下翻:
list/l
-
默认位置显示,上翻:
list/l -

-
从指定的行显示:
list/l 行号

-
从指定的函数显示:
list/l 函数名

-
注:查看时会显示前后文
查看非当前文件代码
-
编译运行并使用
gdb program- 注意:要查看其他文件,需要在生成可执行文件
program时,确保所有源文件都被编译并链接 - 增加swap.h:源文件如下
点击查看代码
#ifndef __SWAP_H #define __SWAP_H void swap(int *a, int *b){ *a ^= *b; *b ^= *a; *a ^= *b; } #endif- 修改program1.c:源代码如下
点击查看代码
#include <stdio.h> #include "swap.h" int sum(int a,int b); int main(int argc, char *argv[]) { for(int i = 0; i < argc; i++){ printf("argv[%d]: %s\n", i, argv[i]); } printf("Hello world\n"); for(int i = 1; i < 5; i++){ printf("%d\n", i); } int a = 1, b = 2; printf("before swap: a=%d, b=%d\n", a, b); printf("a+b = %d\n", sum(a,b)); swap(&a, &b); printf("after swap: a=%d, b=%d\n", a, b); return 0; } int sum(int a, int b){ return a+b; }- 编译链接:gcc -g -Wall program1.c -o program1
- 注意:要查看其他文件,需要在生成可执行文件
-
显示当前调试会话中已加载的源文件列表:
info sources

-
从指定文件指定的行显示:
list/l 文件名:行号

-
从指定文件指定的函数显示:
list/l 文件名:函数名

-
查看及设置显示的行数
- 查看显示的行数:
show list/listsize - 设置显示的行数:
set list/listsize

- 查看显示的行数:
断点操作
-
查看断点:
i/info b/break

-
设置一般断点
b/break 行号b/break 函数名b/break 文件名:行号b/break 文件名:函数

-
设置条件断点(一般用在循环的位置):
b/break 10 if i==5

-
删除断点:
d/del/delete 断点编号

-
设置断点无效:
dis/disable 断点编号

-
设置断点生效:
ena/enable 断点编号

-
忽略断点n次:
ignore 断点编号 忽略次数

调试操作
- 现有断点

-
运行
GDB程序 (重新调试程序)-
程序停在第一行:
start

-
遇到断点才停:
run

-
-
继续运行,到下一个断点停:
c/continue

-
向下执行一行代码(不会进入函数体):
n/next

-
向下单步调试(遇到函数进入函数体)
-
s/step

-
跳出函数体:
finish

-
变量操作/监视
-
打印变量值:
p/print 变量名/表达式

-
打印变量类型:
pt/ptype 变量名/表达式

-
自动变量操作
-
自动打印指定变量的值:
display 变量名

-
查看自动变量:
i/info dis/display

-
取消自动变量:
undis/undisplay 编号

-
其它操作
-
设置变量值:
set var 变量名=变量值 (循环中用的较多)

-
跳出循环:
until 希望跳转到的行号

多线程操作
-
说明:使用gdb调试时,gdb默认只能跟踪一个进程,可以在fork函数调用前,通过指令设置gdb调试工具来跟踪父进程或子进程,默认gdb跟踪父进程
-
调试program2可执行程序

-
查看调试父进程或子进程:
show follow-fork-mode

-
设置调试父进程或子进程:
set follow-fork-mode [parent(default) | child

-
调试模式
-
说明:默认为on,表示调试当前进程时,其余进程继续运行,如果为off,则调试当前进程时,其余进程被gdb挂起
-
查看当前调试模式:
show detach-on-fork

-
设置on:
set detach-on-fork on

-
设置off:
set detach-on-fork off

-
查看当前调试的进程:
i/info i/inferiors- 当设置调试子进程,其余进程为挂起状态时

- 当设置调试子进程,其余进程为挂起状态时
-
切换当前进程的调试:
inferior id- 切换到父进程

- 切换到父进程
-
使进程脱离gdb调试,不再挂起:
detach inferiors id- 子进程脱离挂起状态

- 子进程脱离挂起状态
-

gdb命令,多线程调试
浙公网安备 33010602011771号