Linux C编程(2) dgb调试
1. 首先编写一个用于调试的测试程序test.c
#include <stdio.h> int get_sum(int n) { int sum = 0,i; for(i = 1; i <=n ; i++) { sum+=i; } return sum; } int main() { int i = 100,result; result = get_sum(i); printf("1+2+...+100=%d\n",result); return 0; }
编译并运行
[root@localhost ctest]# gcc test.c -o test [root@localhost ctest]# ./test 1+2+...+100=5050
gdb调试程序的命令格式为:gdb 可执行的程序文件名,加上-q选项可以不输出版权说明
[root@localhost ctest]# gdb -q test Reading symbols from /tmp/ctest/test...(no debugging symbols found)...done. (gdb)
使用q/quit可以退出gdb。
2. 显示和查找程序源代码
(1) list:显示10行代码,再次运行时显示接下来的10行代码
(2) list 5,10:显示5~10行代码
(3) list test.c:5,10:显示源文件test.c中 的5~10行代码,在调试含有多个源文件程序时使用。
(4) list get_sum:显示get_sum函数周围的代码
(5) list test.c:get_sum:显示源文件test.c中get_sum函数周围的代码,在调试多个源文件程序时使用。
例:
(gdb) list 4,10 4 { 5 int sum = 0,i; 6 for(i = 1; i <=n ; i++) 7 { 8 sum+=i; 9 } 10 return sum; (gdb) list get_sum 1 #include <stdio.h> 2 3 int get_sum(int n) 4 { 5 int sum = 0,i; 6 for(i = 1; i <=n ; i++) 7 { 8 sum+=i; 9 } 10 return sum; (gdb)
在调试的过程中如要使用Linux命令,可以在gdb提示符下输入shell命令,如:
(gdb) shell ls datatype.c file1.c num_game.c p3.c symbalconstant.c test test.c digui.c getc.c p2.c sequence.c taijie.c (gdb)
search 和forward用来从当后行向前查找第一个匹配的字符串,reverse-search用来从当前行向前查找第一个匹配的字符串,如:
(gdb) search get_sum 15 result = get_sum(i); (gdb) reverse-search main 12 int main() (gdb)
3. 执行程序和获得帮助
使用gdb -q test只是装入程序,程序并没有运行。运行需输入run命令,如:
(gdb) run Starting program: /tmp/ctest/test 1+2+...+100=5050 Program exited normally. Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6.i686 (gdb)
如果想要详细了解某个命令的使用方法,可以使用help命令,如:
(gdb) help list
(gdb) help all
4. 设置和管理断点
(1) 以行号设置断点,使用break命令,如:
(gdb) break 8 Breakpoint 2 at 0x80483da: file test.c, line 8. (gdb)
第二行为设置断点后的反馈信息,包括:当前设置的断点,断点所在的内存地址及所在行号。输入run后,程序运行到第8行的指令后就暂停。
(gdb) run Starting program: /tmp/ctest/test Breakpoint 2, get_sum (n=100) at test.c:8 8 sum+=i; (gdb)
(2) 以函数名设置断点,如:
(gdb) break get_sum Breakpoint 1 at 0x80483ca: file test.c, line 5. (gdb) run Starting program: /tmp/ctest/test Breakpoint 1, get_sum (n=100) at test.c:5 5 int sum = 0,i; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6.i686 (gdb)
(3) 以条件表达式设置断点,程序在运行过程中,当某个条件满足时,程序在某行中断暂停执行,其格式为:
break 行号或函数名 if 条件
(gdb) break 8 if i==99 Breakpoint 1 at 0x80483da: file test.c, line 8. (gdb) run Starting program: /tmp/ctest/test Breakpoint 1, get_sum (n=100) at test.c:8 8 sum+=i; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6.i686 (gdb)
(4) 不需要指定行号或函数,而是在整个程序运行中当条件表达式的值发生改变时程序就会暂停。,其格式为:
watch 条件表达式
[root@localhost ctest]# gdb -q test Reading symbols from /tmp/ctest/test...done. (gdb) watch i==99 // 由于test没有运行,变量i还没被定义 No symbol "i" in current context. (gdb) break 7 // 设置断点 Breakpoint 1 at 0x80483da: file test.c, line 7. (gdb) run // 运行至断点处 Starting program: /tmp/ctest/test Breakpoint 1, get_sum (n=100) at test.c:8 8 sum+=i; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6.i686 (gdb) watch i==99 // 变量i已定义,可以设置 Hardware watchpoint 2: i==99 (gdb) clear 7 // 删除所设断点 Deleted breakpoint 1 (gdb) continue //程序继续运行,表达式的值从i==99由原来0变到1,因此程序中断 Continuing. Hardware watchpoint 2: i==99 Old value = 0 New value = 1 0x080483e4 in get_sum (n=100) at test.c:6 6 for(i = 1; i <=n ; i++) (gdb) print i // 显示i $1 = 99 (gdb) print sum // 显示sum $2 = 4851 (gdb) next 8 sum+=i; (gdb) print i $3 = 99 (gdb) print sum $4 = 4851 (gdb) next // 继续执行下一条语句 6 for(i = 1; i <=n ; i++) (gdb) print i $5 = 99 (gdb) print sum $6 = 4950 (gdb) next 8 sum+=i; (gdb) print i $7 = 100 (gdb) print sum $8 = 4950 (gdb) next 6 for(i = 1; i <=n ; i++) (gdb) print i $9 = 100 (gdb) print sum $10 = 5050 (gdb)
5. 查看当前设置的中断点
采用info breakpoints命令可以查看当前所有的中断点,如:
(gdb) break 8 Breakpoint 1 at 0x80483da: file test.c, line 8. (gdb) break 16 if result==5050 Breakpoint 2 at 0x8048412: file test.c, line 16. (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x080483da in get_sum at test.c:8 2 breakpoint keep y 0x08048412 in main at test.c:16 stop only if result==5050 (gdb)
Num:编号,Type:类型,Disp:指示中断点在生效一次后是否会失去作用,是位dis,否为keep,End:表明当前中断点是否有效,Adress:表示中断所处的内存地址,What:列出中断发生在哪个函数的第几行,最后一行表明这是一个条件中断。
5. 使中断失效或有效
使用"disable 断点编号"可以是某个断点失效,程序运行到该断点不会停下来而是继续运行。
使用“enable 断点编号”可以使某个断点恢复有效。
(gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x080483da in get_sum at test.c:8 2 breakpoint keep y 0x08048412 in main at test.c:16 stop only if result==5050 (gdb) disalbe 2 Undefined command: "disalbe". Try "help". (gdb) (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x080483da in get_sum at test.c:8 2 breakpoint keep y 0x08048412 in main at test.c:16 stop only if result==5050 (gdb) disable 2 (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x080483da in get_sum at test.c:8 2 breakpoint keep n 0x08048412 in main at test.c:16 stop only if result==5050 (gdb) enable 2 (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x080483da in get_sum at test.c:8 2 breakpoint keep y 0x08048412 in main at test.c:16 stop only if result==5050 (gdb)
6. 删除断点
disable只是让某个某个断点暂时失效,断点依然存在于程序中。彻底删除断点可使用clear或delete命令。
格式为:
(1) clear:删除程序中所有的断点
(2) clear 行号:删除此行的断点
(3) clear 函数名:删除该函数的断点
(4) delete 断点编号:删除指定编号的断点,如果一次要删除多个断点,各个断点编号以空格隔开。
[root@localhost ctest]# gdb -q test Reading symbols from /tmp/ctest/test...done. (gdb) break 6 Breakpoint 1 at 0x80483d1: file test.c, line 6. (gdb) break 7 Breakpoint 2 at 0x80483da: file test.c, line 7. (gdb) break 8 if sum==5050 Note: breakpoint 2 also set at pc 0x80483da. Breakpoint 3 at 0x80483da: file test.c, line 8. (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x080483d1 in get_sum at test.c:6 2 breakpoint keep y 0x080483da in get_sum at test.c:7 3 breakpoint keep y 0x080483da in get_sum at test.c:8 stop only if sum==5050 (gdb) clear 6 Deleted breakpoint 1 (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y 0x080483da in get_sum at test.c:7 3 breakpoint keep y 0x080483da in get_sum at test.c:8 stop only if sum==5050 (gdb) delete 2,3 warning: bad breakpoint number at or near '2,3' (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y 0x080483da in get_sum at test.c:7 3 breakpoint keep y 0x080483da in get_sum at test.c:8 stop only if sum==5050 (gdb) delete 2 3 (gdb) info breakpoints No breakpoints or watchpoints.
7. 查看和设置变量的值
(1) print命令的格式有:
print 变量或表达式:打印变量或表达式当前的值
print 变量=值:对变量进行赋值
print 表达式@要打印的值的个数:打印以表达式值开始的n个数
(2) whatis命令,用于显示某个变量或表达式值的数据类型,七个是我:whatis 变量或表达式
(gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /tmp/ctest/test Breakpoint 1, get_sum (n=100) at test.c:8 8 sum+=i; (gdb) whatis i type = int (gdb) whatis sum+0.5 type = double (gdb)
(3) set命令,用于给变量赋值,其格式为:set variable 变量=值,set也可以针对远程调试进行设置,可以用来设置gdb一行的字符数等。
8. 控制程序的执行
(1) continue命令:让程序继续执行,直到下一个断点或运行完为止。
(2) kill命令:用于结束当前程序的调试。
(3) next和step命令:一次一条执行该代码段,二者的区别是:如果遇到函数调用,next会把该函数当做一条语句来执行,再次输入next会执行函数调用后的语句,而step则会跟踪进入函数,一次一条地执行函数内的代码,直到函数内的代码执行完,才执行函数调用后的语句。
[root@localhost ctest]# gdb -q test Reading symbols from /tmp/ctest/test...done. (gdb) list 1,18 1 #include <stdio.h> 2 3 int get_sum(int n) 4 { 5 int sum = 0,i; 6 for(i = 1; i <=n ; i++) 7 { 8 sum+=i; 9 } 10 return sum; 11 } 12 int main() 13 { 14 int i = 100,result; 15 result = get_sum(i); 16 printf("1+2+...+100=%d\n",result); 17 return 0; 18 } (gdb) break 14 Breakpoint 1 at 0x80483fa: file test.c, line 14. (gdb) run Starting program: /tmp/ctest/test Breakpoint 1, main () at test.c:14 14 int i = 100,result; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6.i686 (gdb) next 15 result = get_sum(i); (gdb) next 16 printf("1+2+...+100=%d\n",result); (gdb) next 1+2+...+100=5050 17 return 0; (gdb)
(gdb) continue Continuing. Program exited normally. (gdb) (gdb) run Starting program: /tmp/ctest/test Breakpoint 1, main () at test.c:14 14 int i = 100,result; (gdb) step 15 result = get_sum(i); (gdb) step get_sum (n=100) at test.c:5 5 int sum = 0,i; (gdb) step 6 for(i = 1; i <=n ; i++) (gdb)
(4) nexti和stepi命令
nexti和stepi命令用来单步执行一条及其指令,注意不是单步执行!一条语句由多条机器指令构成。
例:for(i=0;i<n;i++),如果是单步执行一条指令,则这行语句要输入多个nexti或stepi才能完成,i=0和i<n会分开执行。
(gdb) step 6 for(i = 1; i <=n ; i++) (gdb) stepi 0x080483d8 6 for(i = 1; i <=n ; i++) (gdb) stepi 0x080483e4 6 for(i = 1; i <=n ; i++) (gdb) stepi 0x080483e7 6 for(i = 1; i <=n ; i++) (gdb) stepi 0x080483ea 6 for(i = 1; i <=n ; i++) (gdb) stepi 8 sum+=i;