gdb调试,段错误调试
GDB调试
启动程序准备调试
GDB yourpram
或者
先输入GDB
然后输入 file yourpram
然后使用run或者r命令开始程序的执行,也可以使用 run parameter将参数传递给该程序
参数列表
命令 | 命令缩写 | 命令说明 |
list | l | 显示多行源代码 |
break | b | 设置断点,程序运行到断点的位置会停下来 |
info | i | 描述程序的状态 |
run | r | 开始运行程序 |
display | disp | 跟踪查看某个变量,每次停下来都显示它的值 |
step | s | 执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句 |
next | n | 执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句) |
p | 打印内部变量值 | |
continue | c | 继续程序的运行,直到遇到下一个断点 |
set var name=v |
| 设置变量的值 |
start | st | 开始执行程序,在main函数的第一条语句前面停下来 |
file |
| 装入需要调试的程序 |
kill | k | 终止正在调试的程序 |
watch |
| 监视变量值的变化 |
backtrace | bt | 查看函数调用信息(堆栈) |
frame | f | 查看栈帧 f n 切换到编号为n的栈 |
quit | q | 退出GDB环境 |
//e.c #includevoid debug(char *str) { printf("debug info :%s\n",str ); } main(int argc,char *argv[]){ int i,j; j=0; for(i=0;i<10;i++){ j+=5; printf("now a=%d\n", j); } }
gcc -g -o e e.c
调试gdb e
或者输入gdb
然后 file e
list 命令用法
list命令显示多行源代码,从上次的位置开始显示,默认情况下,一次显示10行,第一次使用时,从代码起始位置显示
gdb) list1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 main(int argc,char *argv[]){7 int i,j;8 j=0;9 for(i=0;i<10;i++){10 j+=5; (gdb)
list n显示已第n行未中心的10行代码
(gdb) list 83 {4 printf("debug info :%s\n",str );5 }6 main(int argc,char *argv[]){7 int i,j;8 j=0;9 for(i=0;i<10;i++){10 j+=5;11 printf("now a=%d\n", j);12 } (gdb)
list functionname显示以functionname的函数为中心的10行代码
(gdb) list main1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 main(int argc,char *argv[]){7 int i,j;8 j=0;9 for(i=0;i<10;i++){10 j+=5; (gdb)
list - 显示刚才打印过的源代码之前的代码
(gdb) list 105 }6 main(int argc,char *argv[]){7 int i,j;8 j=0;9 for(i=0;i<10;i++){10 j+=5;11 printf("now a=%d\n", j);12 }13 }(gdb) list -1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str ); (gdb)
断点命令break
break location:在location位置设置断点,该位置可以为某一行,某函数名或者其它结构的地址
GDB会在执行该位置的代码之前停下来
gdb) list1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 main(int argc,char *argv[]){7 int i,j;8 j=0;9 for(i=0;i<10;i++){10 j+=5; (gdb) 11 printf("now a=%d\n", j);12 }13 }(gdb) break 10Breakpoint 1 at 0x40050a: file e.c, line 10. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:1010 j+=5; (gdb) c Continuing. now a=5Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:1010 j+=5; (gdb) c Continuing. now a=10Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:1010 j+=5; (gdb)
View Code
使用delete breakpoints 断点号 删除断点
这里的断点号表示的是第几个断点,刚才执行break 10返回 reakpoint 1 at 0x40050a: file e.c, line 10.
中的1表示该断点的标号,因此使用 delete breakpoints 1表示删除第10行所定义的断点
clear n表示清除第n行的断点,因此clear 10等同于delete breakpoints 1
disable/enable n表示使得编号为n的断点暂时失效或有效
可使用info查看断点相关的信息
info breakpoints
gdb) info breakpoints No breakpoints or watchpoints. (gdb) break 10Breakpoint 2 at 0x40050a: file e.c, line 10. (gdb) break 9Breakpoint 3 at 0x400501: file e.c, line 9. (gdb) info breakpoints Num Type Disp Enb Address What2 breakpoint keep y 0x000000000040050a in main at e.c:103 breakpoint keep y 0x0000000000400501 in main at e.c:9
display命令
查看参数的值
(gdb) break 10Breakpoint 1 at 0x40050a: file e.c, line 10. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:1010 j+=5; (gdb) display j1: j = 0(gdb) c Continuing. now a=5Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:1010 j+=5;1: j = 5(gdb) display1: j = 5(gdb) display i2: i = 1(gdb) display j3: j = 5(gdb) display j*24: j*2 = 10(gdb) info display Auto-display expressions now in effect: Num Enb Expression4: y j*23: y j2: y i1: y j
View Code
也可以使用disable,enable,delete,info命令修改及查看其状态,用法与对断点的一样
step及next命令
step可使得程序逐条执行,即执行完一条语句然后在吓一跳语句前停下来,等待用户的命令
一般使用step命令是,可使用display或者watch命令查看变量的变化,从而判断程序行为是否符合要求
当下一条指令为函数时,s进入函数内部,在其第一条语句前停下来
step n,next n 表示连续但不执行n条指令,如果期间遇到断点,则停下来
(gdb) list1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 7 main(int argc,char *argv[]){8 int i,j;9 j=0;10 for(i=0;i<10;i++){ (gdb) 11 j+=5;12 printf("now j=%d\n", j);13 debug("x=======x");14 }15 }(gdb) Line number 16 out of range; e.c has 15 lines. (gdb) break 11Breakpoint 1 at 0x40050a: file e.c, line 11. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e1 Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:1111 j+=5; (gdb) s12 printf("now j=%d\n", j); (gdb) s __printf (format=0x400648 "now j=%d\n") at printf.c:3030 { (gdb) bt #0 __printf (format=0x400648 "now j=%d\n") at printf.c:30#1 0x0000000000400525 in main (argc=1, argv=0x7fffffffe538) at e.c:12(gdb) n34 va_start (arg, format); (gdb) n35 done = vfprintf (stdout, format, arg); (gdb) n now j=539 } (gdb) bt #0 __printf (format=<value optimized out>) at printf.c:39#1 0x0000000000400525 in main (argc=1, argv=0x7fffffffe538) at e.c:12(gdb) n main (argc=1, argv=0x7fffffffe538) at e.c:1313 debug("x=======x"); (gdb) n debug info :x=======x10 for(i=0;i<10;i++){ (gdb) s Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:1111 j+=5; (gdb) s12 printf("now j=%d\n", j); (gdb) n now j=1013 debug("x=======x"); (gdb) n debug info :x=======x10 for(i=0;i<10;i++){ (gdb)
View Code
watch
watch可设置观察点(watchpoint)。使用观察点可以使得当某表达式的值发生变化时,程序暂停执行。
执行该命令前,必须保证程序已经运行
(gdb) list 1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 7 main(int argc,char *argv[]){8 int i,j;9 j=0;10 for(i=0;i<10;i++){ (gdb) 11 j+=5;12 printf("now j=%d\n", j);13 debug("x=======x");14 }15 }(gdb) Line number 16 out of range; e.c has 15 lines. (gdb) b main Breakpoint 1 at 0x4004fa: file e.c, line 9. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e1 Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:99 j=0; (gdb) watch j Hardware watchpoint 2: j (gdb) c Continuing. Hardware watchpoint 2: j Old value = 0New value = 5main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=5debug info :x=======x Hardware watchpoint 2: j Old value = 5New value = 10main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j);
View Code
print命令
(gdb) list1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 7 main(int argc,char *argv[]){8 int i,j;9 j=0;10 for(i=0;i<10;i++){ (gdb) 11 j+=5;12 printf("now j=%d\n", j);13 debug("x=======x");14 }15 }(gdb) Line number 16 out of range; e.c has 15 lines. (gdb) break 12Breakpoint 1 at 0x40050e: file e.c, line 12. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e1 Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) p j $1 = 5(gdb) c Continuing. now j=5debug info :x=======x Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) p i,j $2 = 10(gdb) p j $3 = 10(gdb)
View Code
set var name=value
set args 可指定运行时参数(当main函数需要参数时 如:set args 10 20 30 40 50)
show args 命令可以查看设置好的运行参数
在程序运行中动态改变变量的值
(gdb) list1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 7 main(int argc,char *argv[]){8 int i,j;9 j=0;10 for(i=0;i<10;i++){ (gdb) 11 j+=5;12 printf("now j=%d\n", j);13 debug("x=======x");14 }15 }(gdb) Line number 16 out of range; e.c has 15 lines. (gdb) break main Breakpoint 1 at 0x4004fa: file e.c, line 9. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e1 Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:99 j=0; (gdb) watch i Hardware watchpoint 2: i (gdb) watch j Hardware watchpoint 3: j (gdb) c Continuing. Hardware watchpoint 3: j Old value = 0New value = 5main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=5debug info :x=======x Hardware watchpoint 2: i Old value = 0New value = 10x0000000000400533 in main (argc=1, argv=0x7fffffffe538) at e.c:1010 for(i=0;i<10;i++){ (gdb) c Continuing. Hardware watchpoint 3: j Old value = 5New value = 10main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=10debug info :x=======x Hardware watchpoint 2: i Old value = 1New value = 20x0000000000400533 in main (argc=1, argv=0x7fffffffe538) at e.c:1010 for(i=0;i<10;i++){ (gdb) c Continuing. Hardware watchpoint 3: j Old value = 10New value = 15main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=15debug info :x=======x Hardware watchpoint 2: i Old value = 2New value = 30x0000000000400533 in main (argc=1, argv=0x7fffffffe538) at e.c:1010 for(i=0;i<10;i++){ (gdb) c Continuing. Hardware watchpoint 3: j Old value = 15New value = 20main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=20debug info :x=======x Hardware watchpoint 2: i Old value = 3New value = 40x0000000000400533 in main (argc=1, argv=0x7fffffffe538) at e.c:1010 for(i=0;i<10;i++){ (gdb) set var i=8(gdb) c Continuing. Hardware watchpoint 3: j Old value = 20New value = 25main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=25debug info :x=======x Hardware watchpoint 2: i Old value = 8New value = 90x0000000000400533 in main (argc=1, argv=0x7fffffffe538) at e.c:1010 for(i=0;i<10;i++){ (gdb) c Continuing. Hardware watchpoint 3: j Old value = 25New value = 30main (argc=1, argv=0x7fffffffe538) at e.c:1212 printf("now j=%d\n", j); (gdb) c Continuing. now j=30debug info :x=======x Hardware watchpoint 2: i Old value = 9New value = 100x0000000000400533 in main (argc=1, argv=0x7fffffffe538) at e.c:1010 for(i=0;i<10;i++){ (gdb) c Continuing. Watchpoint 2 deleted because the program has left the block inwhich its expression is valid. Watchpoint 3 deleted because the program has left the block inwhich its expression is valid. __libc_start_main (main=0x4004eb , argc=1, ubp_av=0x7fffffffe538, init=<value optimized out>, fini=<value optimized out>, rtld_fini=<value optimized out>, stack_end=0x7fffffffe528) at libc-start.c:258258 exit (result); (gdb) c Continuing. Program exited with code 026.
View Code
函数调用相关的
backtrace
可使用frame 查看堆栈中某一帧的信息
(gdb) list1 #include2 void debug(char *str)3 {4 printf("debug info :%s\n",str );5 }6 7 main(int argc,char *argv[]){8 int i,j;9 j=0;10 for(i=0;i<10;i++){ (gdb) 11 j+=5;12 printf("now j=%d\n", j);13 debug("x=======x");14 }15 }(gdb) Line number 16 out of range; e.c has 15 lines. (gdb) b 13Breakpoint 1 at 0x400525: file e.c, line 13. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/e1 now j=5Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:1313 debug("x=======x"); (gdb) s debug (str=0x400652 "x=======x") at e.c:44 printf("debug info :%s\n",str ); (gdb) bt #0 debug (str=0x400652 "x=======x") at e.c:4#1 0x000000000040052f in main (argc=1, argv=0x7fffffffe538) at e.c:13(gdb) s __printf (format=0x400638 "debug info :%s\n") at printf.c:3030 { (gdb) bt #0 __printf (format=0x400638 "debug info :%s\n") at printf.c:30#1 0x00000000004004e9 in debug (str=0x400652 "x=======x") at e.c:4#2 0x000000000040052f in main (argc=1, argv=0x7fffffffe538) at e.c:13(gdb) s34 va_start (arg, format); (gdb) bt #0 __printf (format=0x400638 "debug info :%s\n") at printf.c:34#1 0x00000000004004e9 in debug (str=0x400652 "x=======x") at e.c:4#2 0x000000000040052f in main (argc=1, argv=0x7fffffffe538) at e.c:13(gdb) s35 done = vfprintf (stdout, format, arg); (gdb) s _IO_vfprintf_internal (s=0x333a58f040, format=0x400638 "debug info :%s\n", ap=0x7fffffffe330) at vfprintf.c:236236 int save_errno = errno; (gdb) bt #0 _IO_vfprintf_internal (s=0x333a58f040, format=0x400638 "debug info :%s\n", ap=0x7fffffffe330) at vfprintf.c:236#1 0x000000333a24effa in __printf (format=<value optimized out>) at printf.c:35#2 0x00000000004004e9 in debug (str=0x400652 "x=======x") at e.c:4#3 0x000000000040052f in main (argc=1, argv=0x7fffffffe538) at e.c:13(gdb) c Continuing. debug info :x=======x now j=10Breakpoint 1, main (argc=1, argv=0x7fffffffe538) at e.c:1313 debug("x=======x"); (gdb) bt #0 main (argc=1, argv=0x7fffffffe538) at e.c:13
View Code
GDB段错误调试
所谓段错误就是对内存的非法访问
采用GDB调试段错误有2种方法
1.在GDB中运行目标程序,当发生段错误时,GDB中运行的程序会自动停下来
2.直接运行目标程序,使其在发生段错误时产生内存转储(core dump)文件,GDB对该文件进行调试
abort.c
#include#include void recurse(void) { static int i; if( ++i == 3) abort(); else recurse(); }int main(int argc,char ** argv){ recurse(); }
gcc -g -o abort abort.c使用gdb调试 Line number 15 out of range; abort.c has 14 lines. (gdb) r Starting program: /mnt/hgfs/www/c/gcc/abort Program received signal SIGABRT, Aborted.0x000000333a232495 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:6464 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); (gdb) bt #0 0x000000333a232495 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64#1 0x000000333a233c75 in abort () at abort.c:92#2 0x00000000004004e7 in recurse () at abort.c:8#3 0x00000000004004ec in recurse () at abort.c:10#4 0x00000000004004ec in recurse () at abort.c:10#5 0x0000000000400502 in main (argc=1, argv=0x7fffffffe528) at abort.c:13显示在recurse函数调用了3次后调用了abort函数,产生段错误
使用内存转储文件
ulimit -a
[root@centos1 gcc]# ulimit -a core file size (blocks, -c) 0data seg size (kbytes, -d) unlimited scheduling priority (-e) 0file size (blocks, -f) unlimited pending signals (-i) 7331max locked memory (kbytes, -l) 64max memory size (kbytes, -m) unlimited open files (-n) 1024pipe size (512 bytes, -p) 8POSIX message queues (bytes, -q) 819200real-time priority (-r) 0stack size (kbytes, -s) 10240cpu time (seconds, -t) unlimited max user processes (-u) 7331virtual memory (kbytes, -v) unlimitedfile locks (-x) unlimited core file size 此时是0
ulimit -c unlimited 设置为不受限制
执行 ./abort 产生内存转储文件
ls 可看到一个名为core且以进程号为后缀的文件
core.6289
gdb abort core.6289
bt
方法同上一个gdb调试