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