Chinaunix首页 | 论坛 | 博客
  • 博客访问: 276291
  • 博文数量: 21
  • 博客积分: 510
  • 博客等级: 下士
  • 技术积分: 545
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-05 12:32
文章分类
文章存档

2013年(3)

2012年(13)

2011年(5)

分类: LINUX

2011-09-14 13:24:13

GDB是Linux下一个功能非常强大的调试工具,习惯之后和图形界面一样方便。下面介绍一下GDB一些常用的命令。
使用GDB调试之前,程序必须能够编译通过,同时加上-g选项。-g是在二进制文件中加入调试信息,这样我们才能够用GDB进行调试代码。如下面的一个Makefile文件,CFLAGS+=-g 就是将调试选项加入到binary中。
  1. 1 CC = gcc
  2. 2 CFLAGS += -g -Wall
  3. 3 APP_NAME := CRC
  4. 4 OBJS = $(APP_NAME).o
  5. 5
  6. 6 .PHONY: all clean
  7. 7 all:$(OBJS)
  8. 8 $(CC) $(CFLAGS) -o $(APP_NAME) $(OBJS)
  9. 9 clean:
  10. 10 rm -f $(APP_NAME) $(OBJS)
  这里我们用一个CRC校验代码CRC.c作为测试文件。
  1. #include<stdio.h>
  2.   2
  3.   3 #define uint16_t unsigned short
  4.   4 #define uint8_t unsigned char
  5.   5
  6.   6 static uint8_t CRC8(uint8_t *pdata,uint8_t len);
  7.   7
  8.   8 int main(int argc, char** argv)
  9.   9 {
  10.  10 uint8_t crc=0;
  11.  11 uint8_t testcrc[]={0x02,0x89,0x29,0x62};
  12.  12 //  uint8_t testcrc[]={0x02};
  13.  13 //  printf("%x CRC result is:%x\n",testcrc,CRC8(testcrc,crc));
  14.  14 crc=CRC8(testcrc,sizeof(testcrc));
  15.  15 }
  16.  16
  17.  17 static uint8_t CRC8(uint8_t *pdata,uint8_t len)
  18.  18 {
  19.  19 uint16_t tmp=*pdata<<8;
  20.  20 uint8_t i;
  21.  21 uint8_t crc;
  22.  22 while(len-->1){
  23.  23 for(i=0;i<8;i++){
  24.  24 if(tmp&0x8000) tmp=(tmp<<1)^0x3100;
  25.  25 else tmp<<=1;
  26.  26 }
  27.  27 pdata++;
  28.  28 crc=(uint8_t)(tmp>>8)^*pdata;
  29.  29 tmp=crc<<8;
  30.  30 printf("%d: 0x%x\n",len,crc);
  31.  31 }
  32.  32 return crc;
  33.  33 }
执行make后,生成binary可执行文件CRC
然后使用命令 
  1. [jzeng8@localhost CRC]$ gdb CRC
进入调试阶段
  1. [jzeng8@localhost CRC]$ gdb CRC
  2. GNU gdb (GDB) Fedora (7.2-16.fc14)
  3. Copyright (C) 2010 Free Software Foundation, Inc.
  4. License GPLv3+: GNU GPL version 3 or later <
  5. This is free software: you are free to change and redistribute it.
  6. There is NO WARRANTY, to the extent permitted by law. Type "show copying"
  7. and "show warranty" for details.
  8. This GDB was configured as "i686-redhat-linux-gnu".
  9. For bug reporting instructions, please see:
  10. <
  11. Reading symbols from /share/CRC/CRC...done.
  12. (gdb) 
敲命令l或者list可以看到代码,一次显示10行,显示完再敲l或者list或者敲回车可以接着显示剩下的代码。
  1. (gdb) list
  2. 1 #include
  3. 2
  4. 3 #define uint16_t unsigned short
  5. 4 #define uint8_t unsigned char
  6. 5
  7. 6 static uint8_t CRC8(uint8_t *pdata,uint8_t len);
  8. 7
  9. 8 int main(int argc, char** argv)
  10. 9 {
  11. 10 uint8_t crc=0;
  12. (gdb) list
  13. 11 uint8_t testcrc[]={0x02,0x89,0x29,0x62};
  14. 12 // uint8_t testcrc[]={0x02};
  15. 13 // printf("%x CRC result is:%x\n",testcrc,CRC8(testcrc,crc));
  16. 14 crc=CRC8(testcrc,sizeof(testcrc));
  17. 15 }
  18. 16
  19. 17 static uint8_t CRC8(uint8_t *pdata,uint8_t len)
  20. 18 {
  21. 19 uint16_t tmp=*pdata<<8;
  22. 20 uint8_t i;
  23. (gdb)
  24. 21 uint8_t crc;
  25. 22 while(len-->1){
  26. 23 for(i=0;i<8;i++){
  27. 24 if(tmp&0x8000) tmp=(tmp<<1)^0x3100;
  28. 25 else tmp<<=1;
  29. 26 }
  30. 27 pdata++;
  31. 28 crc=(uint8_t)(tmp>>8)^*pdata;
  32. 29 tmp=crc<<8;
  33. 30 printf("%d: 0x%x\n",len,crc);
  34. (gdb)
  35. 31 }
  36. 32 return crc;
  37. 33 }
  38. (gdb)
几个常用的调试包括设置断点,全速运行,单步运行,跳出循环,观察变量,打印变量值等。
    GDB设置断点可以用函数名标志,也可以用行号进行设置,效果是一样的,设置完后可以用info break查看断点信息。
  1. (gdb) break main
  2. Breakpoint 1 at 0x80483cd: file CRC.c, line 10.
  3. (gdb) break 10
  4. Note: breakpoint 1 also set at pc 0x80483cd.
  5. Breakpoint 2 at 0x80483cd: file CRC.c, line 10.
  6. (gdb) break CRC8
  7. Breakpoint 3 at 0x804840c: file CRC.c, line 19.
  8. (gdb) info break
  9. Num Type Disp Enb Address What
  10. 1 breakpoint keep y 0x080483cd in main at CRC.c:10
  11. 2 breakpoint keep y 0x080483cd in main at CRC.c:10
  12. 3 breakpoint keep y 0x0804840c in CRC8 at CRC.c:19
  13. (gdb)
如果要消除断点可以用d或者delete消除所有断点,或者clean linenum消除linenum行的断点。
  1. (gdb) clear 10
  2. Deleted breakpoint 4
  3. (gdb) info break
  4. Num Type Disp Enb Address What
  5. 3 breakpoint keep y 0x0804840c in CRC8 at CRC.c:19
  6. (gdb) break main
  7. Breakpoint 5 at 0x80483cd: file CRC.c, line 10.
  8. (gdb) info break
  9. Num Type Disp Enb Address What
  10. 3 breakpoint keep y 0x0804840c in CRC8 at CRC.c:19
  11. 5 breakpoint keep y 0x080483cd in main at CRC.c:10
  12. (gdb) clear main
  13. Deleted breakpoint 5
  14. (gdb) info break
  15. Num Type Disp Enb Address What
  16. 3 breakpoint keep y 0x0804840c in CRC8 at CRC.c:19
  17. (gdb) d
  18. Delete all breakpoints? (y or n) y
  19. (gdb) info break
  20. No breakpoints or watchpoints.
  21. (gdb) 
我们重新设置两个个断点main和CRC8。用命令r或者run可以全速运行程序,碰到断点会停下来,再使用c或者continue可以继续全速运行直到碰到下一个断点或者程序结束。
  1. (gdb) r
  2. The program being debugged has been started already.
  3. Start it from the beginning? (y or n) y
  4. Starting program: /share/CRC/CRC
  5. Breakpoint 1, main (argc=1, argv=0xbffff354) at CRC.c:10
  6. 10 uint8_t crc=0;
  7. (gdb) c
  8. Continuing.
  9. Breakpoint 3, CRC8 (pdata=0xbffff29b "\002\211)b", len=4 '\004') at CRC.c:19
  10. 19 uint16_t tmp=*pdata<<8;
  11. (gdb) c
  12. Continuing.
  13. 3: 0xeb
  14. 2: 0x2
  15. 1: 0x0
  16. Program exited normally.
  17. (gdb)
单步运行的命令是n或者next,一行一行地运行程序,这个命令碰见函数是不会进入函数的。要进入函数的话就要用step或者s。在进入循环的时候,我们可以用until或者u跳出循环体。
  1. (gdb) r
  2. The program being debugged has been started already.
  3. Start it from the beginning? (y or n) y
  4. Starting program: /share/CRC/CRC

  5. Breakpoint 7, main (argc=1, argv=0xbffff354) at CRC.c:10
  6. 10        uint8_t crc=0;
  7. (gdb) s
  8. 11        uint8_t testcrc[]={0x02,0x89,0x29,0x62};
  9. (gdb) s
  10. 14        crc=CRC8(testcrc,sizeof(testcrc));
  11. (gdb) s

  12. Breakpoint 6, CRC8 (pdata=0xbffff29b "\002\211)b", len=4 '\004') at CRC.c:19
  13. 19        uint16_t tmp=*pdata<<8;
  14. (gdb) s
  15. 22        while(len-->1){
  16. (gdb) p len
  17. $4 = 4 '\004'
  18. (gdb) s
  19. 23            for(i=0;i<8;i++){
  20. (gdb) p i
  21. $5 = 130 '\202'
  22. (gdb) s
  23. 24                if(tmp&0x8000)    tmp=(tmp<<1)^0x3100;
  24. (gdb) p i
  25. $6 = 0 '\000'
  26. (gdb) p tmp
  27. $7 = 512
  28. (gdb) s
  29. 25                else tmp<<=1;
  30. (gdb) p tmp
  31. $8 = 512
  32. (gdb) s
  33. 23            for(i=0;i<8;i++){
  34. (gdb) u
  35. 27            pdata++;
  36. (gdb) p pdata
  37. $9 = (unsigned char *) 0xbffff29b "\002\211)b"
  38. (gdb) p *data
  39. Cannot access memory at address 0x0
  40. (gdb) p *pdata
  41. $10 = 2 '\002'
  42. (gdb) s
  43. 28            crc=(uint8_t)(tmp>>8)^*pdata;
  44. (gdb) s
  45. 29            tmp=crc<<8;
  46. (gdb) s
  47. 30            printf("%d: 0x%x\n",len,crc);
  48. (gdb) p tmp
  49. $11 = 60160
  50. (gdb) s
  51. 3:  0xeb
  52. 22 while(len-->1){
  53. (gdb) u
  54. 2:  0x2
  55. 1:  0x0
  56. 32 return crc;
  57. (gdb) 
上面贴出来的部分显示了一个调试过程,不停的用s或者n进行单步运行,用p打印和观察变量值,用u跳出循环体。我们也可以使用watch来观察一个变量,当变量值改变的时候程序会中断。
  调试完成后用q退出GDB。
  1. (gdb) q
  2. [jzeng8@localhost CRC]$








阅读(4493) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~