使用 gdb 之前 ,要使用 gcc -g 源文件 生成包含调试信息的可执行文件。
然后 gdb 可执行文件
首先要明白 断点的基本调试
单步调试 step over 顺序执行每条程序,如果这条程序是一个函数,就不会进入方法体中,而是把这个函数当成一条简单语句执行
单步跳入 ,step into 如果当前行断点是一个方法,则进入当前方法体内。
单步跳出 step out 跳出进入的方法体
以下面的函数为例子 先不打断点 , 使用start 命令 ,相当于 直接单步调试(相当于每行代码一个断点),
1 #include<stdio.h>
2 void fun(void)
3 {
4 for(int i=0;i<10;i++)
5 {
6 printf("fun==> i=%d\n",i);}
7 }
8 int main(int argc,char**argv)
9 {
10
11 int i=0;
12 for(i=0;i<argc;i++)
13 {
14 printf("argv[%d]: %s\n",i,argv[i]);
15 }
16
17
18 fun();
19 printf("hello itcast");
20 return 0;
21 }
如果是按单步调试来 (注意printf 也是函数 ,也可以选择进入)
xxx@xxx-virtual-machine:~/linux$ gdb tt
(gdb) start //使用start 一行一行的执行程序,而 run 是 执行到第一个断点处。
Temporary breakpoint 1 at 0x1198: file testfile.c, line 11.
Starting program: /home/xxx/linux/tt
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4a8) at testfile.c:11
11 int i =0; // 可见从main 函数开始 程序停在了这
(gdb) n // 按n,执行上面那条int i =0;的语句 就是step over 一条一条执行
12 for(i=0;i<argc;i++) //程序停在了这 进入for循环
(gdb) n //按 n 执行上面那条for循环语句。
14 printf("argv[%d]: %s\n",i,argv[i]); //出现了printf函数
(gdb) n //还是选择单步调试 没有进人printf函数中
argv[0]: /home/xxx/linux/tt
12 for(i=0;i<argc;i++) // 退出for循环 程序停在了这
(gdb) n 按n
18 fun(); i //出现了fun () 函数 ,程序停在这里
(gdb) n //选择单步调试(n),不会进入函数体中 ,会把函数当成语句 一次性执行玩
fun==> i=0
fun==> i=1
fun==> i=2
fun==> i=3
fun==> i=4
fun==> i=5
fun==> i=6
fun==> i=7
fun==> i=8
fun==> i=9
19 printf("hello itcast"); //程序停在了这
(gdb) n //按n 单步执行上面的printf语句
20 return 0;
(gdb) n
21 }
(gdb) n
__libc_start_call_main (main=main@entry=0x555555555185 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe4a8) at ../sysdeps/nptl/libc_start_call_main.h:74
74 ../sysdeps/nptl/libc_start_call_main.h: 没有那个文件或目录.
(gdb) Quit
显示行号就说明程序停在了那一行,停在的这行没有被执行。按下n (单步调试之后才被执行)
比如
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4a8) at testfile.c:11
11 int i=0; //实际上 i 还没赋值
(gdb) display i //显示 i 的 值
1: i = 21845 // 因为还没进行 单步调试
(gdb) n //进行单步调试
12 for(i=0;i<argc;i++)
1: i = 0 // i的值为 0
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4a8) at testfile.c:11
11 int i=0;
(gdb) n
12 for(i=0;i<argc;i++) 程序停在了这
(gdb) n //执行上面的for循环,
14 printf("argv[%d]: %s\n",i,argv[i]); 程序停在了这
(gdb) n //执行printf语句
argv[0]: /home/xxx/linux/tt //执行过后的效果
12 for(i=0;i<argc;i++) //程序停在了这
(gdb) n //执行上面的for语句
18 fun(); //程序停在了这
(gdb) s // 单步进入 fun函数
fun () at testfile.c:4
4 for(int i=0;i<10;i++) //程序停
(gdb) n //进入
6 printf("fun==> i=%d\n",i);} //程序停
(gdb) n //执行上面的printf 函数
fun==> i=0 //执行效果
4 for(int i=0;i<10;i++) //程序停
(gdb) n // 进入
6 printf("fun==> i=%d\n",i);} //程序停
(gdb) n //执行上面的printf 函数
fun==> i=1 //执行效果
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=2
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=3
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=4
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=5
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=6
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=7
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=8
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=9
4 for(int i=0;i<10;i++) // 程序停
(gdb) n //进入
7 } //程序停在第 7 行
(gdb) n //条件不满足 ,退出for循环和fun函数
main (argc=1, argv=0x7fffffffe4a8) at testfile.c:19//程序执行到了19行
19 printf("hello itcast"); // 程序停在19 行
(gdb) n //这里没有立刻执行上面的printf
20 return 0; // 程序停在20行
(gdb) n //这里没有立刻结束程序
21 } //程序停在21行 (最后一个括号)
(gdb) n //执行上面的 闭合 main函数后(右括号)
__libc_start_call_main (main=main@entry=0x555555555185 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe4a8) at ../sysdeps/nptl/libc_start_call_main.h:74
74 ../sysdeps/nptl/libc_start_call_main.h: 没有那个文件或目录.
(gdb) n //这一步才打印 ,才正常退出
hello itcast[Inferior 1 (process 8057) exited normally]
(gdb) n
The program is not being run.
对于这种fun函数里有循环结构的,可以使用 until + 行号 结束循环
比如
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4a8) at testfile.c:11
11 int i=0;
(gdb) n
12 for(i=0;i<argc;i++)
(gdb) n
14 printf("argv[%d]: %s\n",i,argv[i]);
(gdb) n
argv[0]: /home/xxx/linux/tt
12 for(i=0;i<argc;i++)
(gdb) n
18 fun();
(gdb) s //单步跳入fun函数
fun () at testfile.c:4
4 for(int i=0;i<10;i++)
(gdb) n //执行for 循环
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=0
4 for(int i=0;i<10;i++)
(gdb) n//执行for 循环
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=1
4 for(int i=0;i<10;i++)
(gdb) until 7 //跳到程序的第7行,
fun==> i=2
fun==> i=3
fun==> i=4
fun==> i=5
fun==> i=6
fun==> i=7
fun==> i=8
fun==> i=9
fun () at testfile.c:7 //直接把for循环执行完了
7 }
(gdb) n
main (argc=1, argv=0x7fffffffe4a8) at testfile.c:19
19 printf("hello itcast");
如果进入fun 函数后又跳出来(使用finish 跳出方法),函数体会当成一条语句执行。
相当于函数体中不中断
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4a8) at testfile.c:11
11 int i=0;
(gdb) n
12 for(i=0;i<argc;i++)
(gdb) n
14 printf("argv[%d]: %s\n",i,argv[i]);
(gdb) n
argv[0]: /home/xxx/linux/tt
12 for(i=0;i<argc;i++)
(gdb) n
18 fun();
(gdb) s // 进入fun函数
fun () at testfile.c:4
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=0
4 for(int i=0;i<10;i++)
(gdb) n
6 printf("fun==> i=%d\n",i);}
(gdb) n
fun==> i=1
4 for(int i=0;i<10;i++)
(gdb) finish //退出fun函数 单步跳入监视 , 它会一直执行到结束
Run till exit from #0 fun () at testfile.c:4
fun==> i=2
fun==> i=3
fun==> i=4
fun==> i=5
fun==> i=6
fun==> i=7
fun==> i=8
fun==> i=9
main (argc=1, argv=0x7fffffffe4a8) at testfile.c:19
19 printf("hello itcast");
(gdb) n
20 return 0;
(gdb) n
21 }
(gdb) n
__libc_start_call_main (main=main@entry=0x555555555185 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe4a8) at ../sysdeps/nptl/libc_start_call_main.h:74
74 ../sysdeps/nptl/libc_start_call_main.h: 没有那个文件或目录.
(gdb) n
hello itcast[Inferior 1 (process 8208) exited normally]
(gdb) n
The program is not being run.
值得注意的是,printf函数也可以单步跳入
如果进入printf ,情况 如下
以 下面程序为例
1 #include<stdio.h>
2 int main()
3 {
4
5 printf("hello world");
6 printf("I like the code ");
7 return 0;
8
9 }
单步调试 不进入printf
Temporary breakpoint 1, main () at print.c:5
5 printf("hello world"); //停在第 5行
(gdb) n //执行完上面的printf
6 printf("I like the code "); // 停在第 6行
(gdb) n //执行完上面的printf
7 return 0;
(gdb) n
9 } //停在最后一行
(gdb) n //执行最后一个括号
__libc_start_call_main (main=main@entry=0x555555555149 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe498) at ../sysdeps/nptl/libc_start_call_main.h:74
74 ../sysdeps/nptl/libc_start_call_main.h: 没有那个文件或目录.
(gdb) n //也同样是在main函数闭合之后才会打印 和结束程序
hello worldI like the code [Inferior 1 (process 8114) exited normally]
(gdb) n
The program is not being run.
如果进入printf 函数
warning: Source file is more recent than executable.
5 printf("hello world"); //停在第5行
(gdb) s //单步跳入 printf函数
__printf (format=0x555555556004 "hello world") at ./stdio-common/printf.c:28
28 ./stdio-common/printf.c: 没有那个文件或目录.
(gdb) finish //退出函数
Run till exit from #0 __printf (format=0x555555556004 "hello world") at ./stdio-common/printf.c:28
main () at print.c:6
6 printf("I like the code "); //停在第6行
Value returned is $1 = 11
(gdb) s //进入第六行的printf函数
__printf (format=0x555555556010 "I like the code ") at ./stdio-common/printf.c:28
28 ./stdio-common/printf.c: 没有那个文件或目录.
(gdb) finish //退出函数
Run till exit from #0 __printf (format=0x555555556010 "I like the code ") at ./stdio-common/printf.c:28
main () at print.c:7
7 return 0;
Value returned is $2 = 16
(gdb) n
9 } //停在最后一个括号处
(gdb) n //执行最后一个括号
__libc_start_call_main (main=main@entry=0x555555555149 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe498) at ../sysdeps/nptl/libc_start_call_main.h:74
74 ../sysdeps/nptl/libc_start_call_main.h: 没有那个文件或目录.
(gdb) n //也同样是在main函数闭合之后才会打印 和结束程序
hello worldI like the code [Inferior 1 (process 8186) exited normally]
(gdb) n
The program is not being run.
(force step into ) 用于进入系统自带的函数或方法。 只在 Clion的图形化界面有
(resume program) 恢复程序运行,但如果该断点下面代码还有断点则停在下一个断点上 对应gdb 命令的 continue 简写为c (前提是先打断点,使用run 命令 ,而不是 start 命令)
对应gdb 命令的 quit 简写为 q
如果不设置断点 也不 执行start ,程序就会一次性执行完(就像执行了 run )
b + 行号
b + 函数名
如果是多文件
b + filename : 行号
b+ filename : function
b + class :: function 或 b+ class ::function (type,type) 考虑重载
i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x000055555555515e in fun at testfile.c:6
stop only if i==6
breakpoint already hit 1 time
2 breakpoint keep y 0x0000555555555155 in fun at testfile.c:4
3 breakpoint keep y 0x000055555555515e in fun at testfile.c:6
4 breakpoint keep y 0x0000555555555198 in main at testfile.c:11
b testfile.c : 8 if Value ==5
Reading symbols from tt...
(gdb) b 6 if i==6 //设置 条件断点 第六行 ,如果 i 为 6 就停下
Breakpoint 1 at 0x115e: file testfile.c, line 6.
(gdb) run
Starting program: /home/xxx/linux/tt
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
argv[0]: /home/xxx/linux/tt
fun==> i=0
fun==> i=1
fun==> i=2
fun==> i=3
fun==> i=4
fun==> i=5
Breakpoint 1, fun () at testfile.c:6
6 printf("fun==> i=%d\n",i);}
(gdb)
d +断点
dis + 断点
ena + 断点
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x000055555555515e in fun at testfile.c:6
stop only if i==6
breakpoint already hit 1 time
2 breakpoint keep y 0x0000555555555155 in fun at testfile.c:4
3 breakpoint keep y 0x000055555555515e in fun at testfile.c:6
4 breakpoint keep y 0x0000555555555198 in main at testfile.c:11
(gdb) dis // 不指定的话,会让所有断点失效
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep n 0x000055555555515e in fun at testfile.c:6
stop only if i==6
breakpoint already hit 1 time
2 breakpoint keep n 0x0000555555555155 in fun at testfile.c:4
3 breakpoint keep n 0x000055555555515e in fun at testfile.c:6
4 breakpoint keep n 0x0000555555555198 in main at testfile.c:11
自动(每次单步的时候)显示变量
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4a8) at testfile.c:11
11 int i=0;
(gdb) display i
1: i = 21845
(gdb) n
12 for(i=0;i<argc;i++)
1: i = 0
(gdb) n
14 printf("argv[%d]: %s\n",i,argv[i]);
1: i = 0
(gdb) n
argv[0]: /home/xxx/linux/tt
12 for(i=0;i<argc;i++)
1: i = 0
(gdb) n
18 fun();
1: i = 1
(gdb) n
fun==> i=0
fun==> i=1
fun==> i=2
fun==> i=3
fun==> i=4
fun==> i=5
fun==> i=6
fun==> i=7
fun==> i=8
fun==> i=9
19 printf("hello itcast");
1: i = 1
(gdb)
查看变量 的类型
ptype 变量名
打印变量的值
p 变量名
l + 行数
l默认查看 10行,可以设置默认大小
set listsize count
显示 默认大小
show listsize
多文件查看源代码 和 多文件设置 断点的方法相同
以下面的代码为例
1 #include<stdio.h>
2 void fun(void)
3 {
4 for(int i=0;i<10;i++)
5 {
6 printf("fun==> i=%d\n",i);}
7 }
8 int main(int argc,char**argv)
9 {
10
11 int i=0;
12 for(i=0;i<argc;i++)
13 {
14 printf("argv[%d]: %s\n",i,argv[i]);
15 }
16
17
18 fun();
19 printf("hello itcast");
20 return 0;
21 }
设置参数
set args 10 20 30 40 50
显示设置的参数
show args
演示
Reading symbols from a.out...
(gdb) set args 10 20 30 40 50 60
(gdb) show args
Argument list to give program being debugged when it is started is "10 20 30 40 50 60".
(gdb) run
Starting program: /home/xxx/linux/a.out 10 20 30 40 50 60
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
argv[0]: /home/xxx/linux/a.out
argv[1]: 10
argv[2]: 20
argv[3]: 30
argv[4]: 40
argv[5]: 50
argv[6]: 60
fun==> i=0
fun==> i=1
fun==> i=2
fun==> i=3
fun==> i=4
fun==> i=5
fun==> i=6
fun==> i=7
fun==> i=8
fun==> i=9
hello itcast[Inferior 1 (process 13986) exited normally]
(gdb)
在Colin 中的断点调试

