• linux下如何使用gdb调试


    gdb是linux下非常好用的一个调试工具,虽然它是命令行模式的调试工具,但是它的功能强大到你无法想象,这里简单介绍下gdb下常用的命令。

    首先编译生成可执行文件(这里的test.c是一个简单的求前n项和的程序)。

    gcc -g test.c -o test(-g选项告诉gcc在编译程序时加入调试信息)。
    接下来可以这样。

    gdb test

    然后你就会看到出现好多信息在屏幕上,大致说的是gdb的一些版本信息说明之类的,但是它对你调试程序没用呀,所以,你可以加上-q选项,不输出它们。

    gdb -q test

    wang@king:~$ gdb -q test
    Reading symbols from test...done.
    (gdb) 

    有没有觉得这个世界一下子清净了许多。

    也可以先进入gdb模式,然后再加载文件。

    wang@king:~$ gdb -q
    (gdb) file test
    Reading symbols from test...done.
    (gdb) 

    好了,现在开始调试了,但是我还想看看我的代码怎么办,gdb提供了一条命令,可以让你的程序显示出来。

    (gdb)                                       //list默认一次显示10行
    1    #include<stdio.h>
    2    int func(int n)
    3    {
    4        int i;
    5        int sum=0;
    6        for(i=0;i<n;i++)
    7            {
    8                sum+=i;
    9            }
    10        return sum;
    (gdb)                                       //直接输入回车重复上次命令,显示接下来的10行
    11    }
    12    int main()
    13    {
    14        int n;
    15        printf("请输入n的值");
    16        scanf("%d",&n);
    17        printf("1+2+..+%d=%d",n,func(n));
    18        return 0;
    19    }
    (gdb) 
                

    list默认参数可以用show listsize来查看,如果感觉10行太多或者太少,还可以用set listsize <count>来更改。

    list 还可以加上其他参数,比如:
    list 5,10   显示第5行到第10行的代码;

    list func   显示func函数周围的代码,显示范围和list参数有关;

    list test.c:5,10  显示源文件test.c第5行到第10行的代码,一般用于调试含多个源文件的程序。

    gdb 还支持字符串查找,search str,从当前行开始,向前查找含str的字符串;

    reverse-search str,从当前行开始,向后查找含str的字符串。

    现在你的屏幕应该被占满了吧?想清空屏幕,可是还在gdb里面呀,怎么办?其实,gdb也支持运行linux命令的,可以在gdb的提示符中,输入shell,然后在输入你需要的命令就可以了

    (gdb) shell clear

    这样也能达到清屏的效果。

    看了程序的代码,感觉第6行代码可能有点问题,现在就需要我就需要设置一个断点,让程序停在第6行之前。

    (gdb) break 6
    Breakpoint 1 at 0x80484c8: file test.c, line 6.
    (gdb) 

    下面一行的 信息,1说明我设置的这个断点是第一个断点,断点所在内存地址为0x80484c8,它在文件test.c的第6行。

    gdb还可以以条件表达式设置断点。

    (gdb) break 7 if n==6
    Breakpoint 2 at 0x80484d1: file test.c, line 7.
    (gdb) 

    这个断点的含义是,如果n的值为6,则程序运行到第7行停止。

    当然,还可以直接在某个函数处设置断点;直接break 函数名就可以了,

    然后我们想看下设置的断点信息,可以使用info breakpoints命令。

    (gdb) info breakpoints
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080484c8 in func at test.c:6
    2       breakpoint     keep y   0x080484d1 in func at test.c:7
        stop only if n==6
    4       breakpoint     keep y   0x080484c1 in func at test.c:5
    (gdb) 

    Num表示断点的编号;Type表示断点的断点的类型,第二个断点类型还加上了条件;Disp表示中断点在执行一次之后是否失去作用,dis为是,keep为不是;Enb表示当前中断点是否有效,y为是,n为否;Address表示中断点所处的内存地址;What指出断点所处的位置。

    如果不需要程序在该断点暂停时,有两种方法,一种是使该断点失效,一种是直接删除该断点。

    (gdb) disable 1
    (gdb) info breakpoints
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep n   0x080484c8 in func at test.c:6
    2       breakpoint     keep y   0x080484d1 in func at test.c:7
        stop only if n==6
    3       breakpoint     keep y   0x080484c1 in func at test.c:5
    (gdb) 

    可以看到,第一个断点的Enb变为n了,表示该断点已经无效了,如果需要恢复,可以使用enable命令。这里需要注意的是,disable后面的参数为断点的编号。而不是行号。

    直接删除该断点,可以使用clear命令和delete命令。

    (gdb) clear 6
    已删除的断点 1 
    (gdb) 

    clear命令后面的参数为设置断点的行号,clear后面参数还可以加设置断点的函数名。

    delete命令后面的参数为断点的编号;可以一次删除多个断点,断点编号之间用空格隔开;如果delete后没有参数,默认删除所以断点,会给出提示选择是否操作。

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

    断点设置好了,现在就可以调试了,

    (gdb) run                                                //开始执行程序
    Starting program: /home/wang/test 
    请输入n的值10
    
    Breakpoint 1, func (n=10) at test.c:6     //设置的第一个断点,程序在第6行暂停
    6        for(i=0;i<n;i++)
    (gdb) continue                                      //让程序继续运行,直到下个断点或者结束
    Continuing.
    
    Breakpoint 2, func (n=10) at test.c:8    //第二个断点设置的是i==6时停止
    8                sum+=i;
    (gdb) print i                                          //用print命令打印出i的值
    $1 = 6
    (gdb) print sum
    $2 = 15
    (gdb) next                                          //继续执行下一条语句,只执行一条。
    6        for(i=0;i<n;i++)
    (gdb) next    
    8                sum+=i;
    (gdb) print i
    $3 = 7
    (gdb) continue    
    Continuing.
    1+2+..+10=45[Inferior 1 (process 23636) exited normally]    
    (gdb) quit                                             //退出gdb调试
                                                

     上面出现了很多命令,下面就来说说都是怎么用的。

    run,开始运行程序;

    continue,程序暂停时继续运行程序的命令;

    print 变量名或表达式,打印该变量或者该表达式的值。whatis 变量名或者表达式,可以显示该变量或表达式的数据类型。

    print  变量=值,这种形式还可以给对应的变量赋值;类似的还有set variable 变量=值。作用和用print赋值相同。

    next,继续执行下一条语句;还有一条命令step,与之类似,不同的是,当下一条语句遇到函数调用的时候,next不会跟踪进入函数,而是继续执行下面的语句,而step命令则会跟踪进入函数内部。

    (gdb) run
    Starting program: /home/wang/test 
    
    Breakpoint 1, main () at test.c:16
    16        scanf("%d",&n);
    (gdb) next
    请输入n的值10  
    17        printf("1+2+..+%d=%d",n,func(n));
    (gdb) next                                             //next命令直接执行下一行,没有进入func函数  
    18        return 0;
    (gdb)
    (gdb) run
    Starting program: /home/wang/test 
    
    Breakpoint 1, main () at test.c:16
    16        scanf("%d",&n);
    (gdb) n
    请输入n的值10
    17        printf("1+2+..+%d=%d",n,func(n));
    (gdb) step                  //step命令跟踪进入了func函数  
    func (n=10) at test.c:5
    5        int sum=0;
    (gdb) 
    
    

     还有nexti和stepi命令,这两个是单步执行一条机器指令,比如(i=0;i<n;i++)这条语句需要输入多个nexti才能执行完;两个的区别和上面相同。

    quit,退出gdb调试,如果调试中想要退出,可以直接输入该命令,会出现提示选择是否退出。kill命令,结束当前程序的调试,(不会退出gdb)。

    (gdb) quit
    A debugging session is active.
    
        Inferior 1 [process 32229] will be killed.
    
    Quit anyway? (y or n) 
  • 相关阅读:
    php date 时间差
    array_merge 和 + 号的的区别
    apache 添加https后导致http无法访问
    php 获取url
    TP5 事务处理
    LeetCode 每日一题 (盛最多水的容器)
    LeetCode 每日一题 (字符串转换整数 (atoi))
    LeetCode 每日一题(5. 最长回文子串)
    LeetCode 每日一题 (3 无重复字符的最长子串)
    LeetCode 每日一题 (两数相加)
  • 原文地址:https://www.cnblogs.com/kingos/p/4514756.html
Copyright © 2020-2023  润新知