首页 > 代码库 > gdb的基本调试方法

gdb的基本调试方法

1.怎么调试程序

在linux下,我们通常用gcc来编译链接程序,用gdb来调试程序。在用gcc生成程序的时候,用-g选项来使程序可以调试:

test@test-ThinkPad-Edge-E420s:~/gdb$ gcc -g -Wall gdbtest.c -o gdbtest

然后在用如下命令调试程序:

test@test-ThinkPad-Edge-E420s:~/gdb$ gdb gdbtest

2.gdb的基本命令介绍

run在gdb中运行你的程序,一般会在你设置的断点地方停止。
start也是在gdb中运行程序,不过默认实在程序的main函数停止。
break用break命令在程序中来设置断点,方便程序的调试。
continuecontinue继续执行程序,直到遇到下一个断点。
stepstep单步调试程序,遇到有函数调用的地方,会跳进该函数,继续单步调试。
nextnext也是单步调试程序,但是在函数的调用的地方,不会跳进该函数,二回继续执行。
listlist列出当前的源代码,如果参数是函数名,就会列出该函数的定义。
print用来打印变量。
display 用来显示变量的。
backtrace用来显示函数的调用栈。

3.设置断点的基本方法

break linenumber
b linenumber
在当前文件的第linenumber行设置一个断点。
break functionname
b functionname
在当前文件的functionname函数设置一个断点
break filename:linenumber
b filename:linenumber
在filename文件第linenumber行设置一个断点。
break filename:functionname
b filename:functionname
在filename文件的functionname函数设置一个断点。

(gdb) l
        38        int x = atoi(argv[1]);
        39        int y = atoi(argv[3]);
        40        printf("x = %d, y = %d.\n", x , y);
        41   
        42        if (0 == strcmp("+", argv[2])) {
        43            int result = add(x, y);
        44            printf("%s %s %s = %d.\n", argv[1], argv[2], argv[3], result);
        45        }
        46   
        47        if (0 == strcmp("-", argv[2])) {

在43的一行设置一个断点:

(gdb) b 43
            Breakpoint 2 at 0x80485dc: file gdbtest.c, line 43.

在add函数设置一个断点:

(gdb) b add
            Breakpoint 3 at 0x8048500: file gdbtest.c, line 7.

在sub函数设置一个断点:

(gdb) b sub
            Breakpoint 4 at 0x804850d: file gdbtest.c, line 12.

在div函数设置一个断点:

(gdb) b div
            Breakpoint 5 at 0xb7e487e0: file div.c, line 56.

用info break(i   b)查看当前设置的断点信息:

(gdb) info break
            Num     Type           Disp Enb Address    What
            2       breakpoint     keep y   0x080485dc in main at gdbtest.c:43
            3       breakpoint     keep y   0x08048500 in add at gdbtest.c:7
            4       breakpoint     keep y   0x0804850d in sub at gdbtest.c:12
            5       breakpoint     keep y   0xb7e487e0 in div at div.c:56

用delete删除设置的断点(删除断点的方法设置的时候都差不多):

(gdb) delete 5
(gdb)
i b
            Num     Type           Disp Enb Address    What
            2       breakpoint     keep y   0x080485dc in main at gdbtest.c:43
            3       breakpoint     keep y   0x08048500 in add at gdbtest.c:7
            4       breakpoint     keep y   0x0804850d in sub at gdbtest.c:12

第5个断点没有了。

直接用delete删除所有设置的断点:

(gdb) delete
            删除所有断点吗? (y or n) n

disable命令使某个断点失效:

(gdb) disable 3

(gdb) i b
            Num     Type           Disp Enb Address    What
            2       breakpoint     keep y   0x080485dc in main at gdbtest.c:43
            3       breakpoint     keep n   0x08048500 in add at gdbtest.c:7
            4       breakpoint     keep y   0x0804850d in sub at gdbtest.c:12

enable命令是某个断点有效:

(gdb) enable 3
(gdb)
i b
            Num     Type           Disp Enb Address    What
            2       breakpoint     keep y   0x080485dc in main at gdbtest.c:43
            3       breakpoint     keep y   0x08048500 in add at gdbtest.c:7
            4       breakpoint     keep y   0x0804850d in sub at gdbtest.c:12

只执行disable命令就是让所有断点失效:

(gdb) disable
(gdb)
i b
            Num     Type           Disp Enb Address    What
            2       breakpoint     keep n   0x080485dc in main at gdbtest.c:43
            3       breakpoint     keep n   0x08048500 in add at gdbtest.c:7
            4       breakpoint     keep n   0x0804850d in sub at gdbtest.c:12

只执行enable命令就是让所有断点有效:

(gdb) enable
(gdb)
i b
            Num     Type           Disp Enb Address    What
            2       breakpoint     keep y   0x080485dc in main at gdbtest.c:43
            3       breakpoint     keep y   0x08048500 in add at gdbtest.c:7
            4       breakpoint     keep y   0x0804850d in sub at gdbtest.c:12

 4.gdb打印变量

在gdb可以用print/p命令来打印变量,打印的方式可以分为以下几种:

x按十六进制格式显示变量。
d按十进制格式显示变量。
u按十六进制格式显示无符号整型
o按八进制格式显示变量
t按二进制格式显示变量
a按十六进制格式显示变量
c按字符格式显示变量
f按浮点数格式显示变量

(gdb) l
            1    #include <stdio.h>
            2   
            3    int main(void)
            4    {
            5        char a[100];
            6        int i;
            7   
            8        for (i = 0; i < 100; i++) {
            9        a[i] = i;
            10      }

            11     return 0;

            12  }

(gdb) start
            Temporary breakpoint 1 at 0x8048447: file print.c, line 4.
            Starting program: /home/test/gdb/print

            Temporary breakpoint 1, main () at print.c:4
             4    {

(gdb) u 11
            main () at print.c:12
            12        return 0;

以十六进制打印数组a的内容,会显示很多:

(gdb) p/x a
             $1 = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
               0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
               0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
               0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d,
               0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63}

可以用p *array_name@ count打印数组array_name的前count个元素。

以十六进制指定打印数组的前面十个元素:

(gdb) p/x *a@10
              $2 = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}

在c语言中经常有很多struct自定义变量,在程序的执行的可以通过whatis命令和ptype这俩个命令来查看变量类型。

(gdb) l -15
1    #include <stdio.h>
2   
3    typedef struct listnode
4    {
5        int value;
6        struct listnode *next;
7    }Node;
8   
9    Node node1 = {1, NULL};
10   
(gdb)
start
    Temporary breakpoint 1 at 0x80483f3: file struct.c, line 13.
    Starting program: /home/test/gdb/struct

    Temporary breakpoint 1, main () at struct.c:13
    13        Node node2 = {2, NULL};
(gdb) n
    15        return 0;

查看node1的变量类型,没有到结构体,只显示类型:

(gdb) whatis node1
             type = Node

查看node2的变量类型,看到结构体里面都有些什么:

(gdb) ptype node2
             type = struct listnode {
                      int value;
                      struct listnode *next;
            }

gdb中使用“x”命令来打印内存的值,格式为“x/nfu addr”。含义为以f格式打印从addr开始的n个长度单元为u的内存值。参数具体含义如下:
a)n:输出单元的个数。
b)f:是输出格式。比如x是以16进制形式输出,o是以8进制形式输出,等等。
c)u:标明一个单元的长度。b是一个byteh是两个byte(halfword),w是四个byte(word),g是八个byte(giant word)。

(gdb) l
    1    #include <stdio.h>
    2   
    3    int main(void)
    4    {
    5        char a[100];
    6        int i;
    7   
    8        for (i = 0; i < 100; i++) {
    9        a[i] = i;
    10        }
    (gdb)
start
    Temporary breakpoint 1 at 0x8048447: file print.c, line 4.
    Starting program: /home/test/gdb/print

    Temporary breakpoint 1, main () at print.c:4
    4    {
(gdb)
n
        8        for (i = 0; i < 100; i++) {
(gdb)
n
        9        a[i] = i;
(gdb)
n
        8        for (i = 0; i < 100; i++) {
(gdb)
u 11
        main () at print.c:12
        12        return 0;

以16进制格式打印数组前a16个byte的值:

(gdb) x/16xb a
        0xbfffedf8:    0x00    0x01    0x02    0x03    0x04    0x05    0x06    0x07
        0xbfffee00:    0x08    0x09    0x0a    0x0b    0x0c    0x0d    0x0e    0x0f

以无符号10进制格式打印数组a前16个byte的值:

(gdb) x/16ub a
        0xbfffedf8:    0    1    2    3    4    5    6    7
        0xbfffee00:    8    9    10    11    12    13    14    15

以16进制格式打印数组a前16个word(4个byte)的值:

(gdb) x/16xw a
        0xbfffedf8:    0x03020100    0x07060504    0x0b0a0908    0x0f0e0d0c
        0xbfffee08:    0x13121110    0x17161514    0x1b1a1918    0x1f1e1d1c
        0xbfffee18:    0x23222120    0x27262524    0x2b2a2928    0x2f2e2d2c
        0xbfffee28:    0x33323130    0x37363534    0x3b3a3938    

gdb的基本调试方法