当前位置: 首页 > article >正文

【Linux】gdb/cgdb调试工具

目录

前言:

一、安装gdb/cgdb

二、调试可执行程序 

1.release版本和debug版本的区别

2.调试程序(命令讲解)

2.1 l n(罗列第n行代码)

2.2 r(运行代码)

2.3 b n(在第n行设置断点)

2.4 info b(查看断点信息)

2.5 d n(删除ID为n断点) 

2.6 disable n/enable n(禁用断点/启用断点)

2.7 n / s(逐过程/逐语句) 

2.8 display 变量名/undisplay 变量名(监视变量并常显示/取消显示)

2.9 p 变量名(显示一次变量值)

2.10 bt(查看函数堆栈)

2.11 until(执行到指定行) 

3.使用cgdb

4.使用cgdb发现bug(及命令补充)

4.1 c(跳至下个断点运行)

4.2 finish(立即执行完当前函数) 

4.3 info locals(自动窗口)

4.4 watch(监视可能改变的值)

4.5 set var(改变设置的值)

5.条件断点 

5.1 新增条件断点

5.2 给条件断点新增条件 

三、命令汇总 

总结: 


前言:

在 Linux 环境中,GDB(GNU Debugger)是一个强大的调试工具。但是这里建议使用cgdb(后面说)。本篇就要来给大家讲解这两种调试工具,并掌握他们的命令。

一、安装gdb/cgdb

当然,要想使用gdb,我们要先安装gdb。

我们使用gdb --version来查看版本。

没有就:

sudo yum install -y gdb

但是gdb不好使用,我们推荐使用另一个工具cgdb,还是要先安装:

sudo yum install -y cgdb

二、调试可执行程序 

我们知道,一个可执行程序分为两种,一种是debug(含有调试信息),一种是release(取消调试信息)。

gcc/g++编译程序默认生成release版本。要生成debug版本需要加上-g选项。

我们创建一个code.c文件,并写入以下代码:

#include<stdio.h>

int sum(int s, int e) 
{
    int sum = 0;
    int i = s;
    for (; i < e; ++i) 
    {
        sum += i;
    }
    return sum;
}

int main()
{
    printf("process is runing\n");

    int start = 1;
    int end = 100;
    int result = sum(start, end);
    printf("process is done, result: %d\n", result);

    return 0;
}

1.release版本和debug版本的区别

我们先使用gcc -o myexe code.c生成一个release版本的myexe程序;之后使用gcc -o myexe-debug code.c生成一个debug版本的myexe-debug程序。

gcc -o myexe code.c
gcc -o myexe-debug code.c -g

 之后使用readelf命令来显示ELF(Executable and Linkable Format)格式目标文件的信息工具。其中-S选项为显示节头表信息。

所以我们在makefile中这样写:

此时就可以gdb myexe了。

2.调试程序(命令讲解)

GDB(GNU Debugger)是一个强大的调试工具,主要用于调试程序。此时我们就利用它开始调试。

注意:必须是debug版本的可执行程序!

此时就进入了gdb交互模式,直接q会进行退出。

2.1 l n(罗列第n行代码)

l 1命令从第一行开始显示,之后一共显示10行,每次点击回车会自动执行上一次的命令。

可以使用l命令罗列源代码。 gdb会记录最新的一条命令,直接回车就是执行。

2.2 r(运行代码)

我们在gbd中可以直接r运行代码。

2.3 b n(在第n行设置断点)

我们平时喜欢在VS中设置一个断点,之后可以F5,开始执行并调试。

当我们想打断点时,可以 b 行数 (这里b相当于breakpoint),比如在19行打上断点。

打断点的方式有多种,比如:

2.4 info b(查看断点信息)

info b可以去查看断点信息,d可以删除断点(要按照断点编号删除),比如此时我们打上多个断点:

2.5 d n(删除ID为n断点) 

在2.4中有示例。

2.6 disable n/enable n(禁用断点/启用断点)

有时候我们并不想直接删除断点,而是禁用断点,比如VS中(当然也可开启):

gdb也可以:

2.7 n / s(逐过程/逐语句) 

r也可以直接运行到断点处(也就是执行并调试)。在VS中可以逐过程或者逐语句:

gdb也可以:

所以, 在gdb中同样可以使用n(逐过程不进入函数内部)和s(逐语句进入函数内部)去进行调试。

2.8 display 变量名/undisplay 变量名(监视变量并常显示/取消显示)

其实VS中有很多窗口,比如自动窗口、监视窗口、内存窗口等。gbd中也可以常显示我们要监视的变量,也就是display 变量名(比如:display i。监视i变量)。

我们也可以使用 undisplay 变量名编号 取消常显示。

2.9 p 变量名(显示一次变量值)

当我们只是想临时的看一个变量,可以使用p,打印此时我们要观察变量的值。

2.10 bt(查看函数堆栈)

bt是调用堆栈,也就是看那些函数在堆栈中。

2.11 until(执行到指定行) 

此时我们在循环内部执行代码,要执行99次,这样效率就会很低下,所以我们可以使用until直接跳转到制定行数。

3.使用cgdb

我们接下来使用cgdb对刚才的debug版本程序调试:

可以发现cgdb可以把代码可视化出来。

4.使用cgdb发现bug(及命令补充)

此时我们故意往代码中添加一些错误:

#include<stdio.h>

int sum(int s, int e) 
{
    int sum = 0;
    int i = s;
    for (; i < e; ++i) 
    {
        sum += i;
    }
    return sum;
}

int Add(int x, int y)
{
    return x + y;
}

int div(int x, int y)
{
    int z = x /y;
    return z;
}

int main()
{
    printf("process is runing\n");

    int start = 1;
    int end = 100;
    int result = sum(start, end);
    printf("process is done, result: %d\n", result);
    printf("process is done, Add: %d\n", Add(10, 20));
    printf("process is done, div: %d\n", div(10, 0));

    return 0;
}

此时直接运行程序崩溃, 我们就需要进行调试了。

此时我们在3个函数上面分别设置一个断点(sum函数、Add函数、div函数),调试sum函数之后程序没有崩溃。

4.1 c(跳至下个断点运行)

要在下一个断点处直接运行就是用c命令,直接在下一个断点处继续运行。

VS中继续点F5进入下一个断点执行,此时我们就准确的知道了到底是在哪里崩溃的。

此时我们就准确的知道了到底是在哪里崩溃的 ,再次运行cgdb并直接设置断点,最终确定了问题。

4.2 finish(立即执行完当前函数) 

这里一共有3个函数,当我们设置好断点进入函数以后,我们想立即执行完当前所在函数,可以使用finish立即执行完当前函数。

总结:断点 + finish + until + c 这几个命令可以对大的代码块进行debug。

此时我们修正代码:

4.3 info locals(自动窗口)

VS中有一个自动窗口(就是自动看当前执行步骤中有哪些变量并打印出来对应的值),gdb对应的也就是info locals。

4.4 watch(监视可能改变的值)

当我们在调试的时候,要监视哪些值有没有发生变换,就可以在调试的时候使用watch来监视对应变量。

4.5 set var(改变设置的值)

这个就是当我们在调试的时候,比如当时是从1(s变量)加到99(e变量),此时我们可能会感觉太大了,我们再调试的时候设置e的值,比如此时我们求1加到4的值就把e设置为5。

5.条件断点 

在VS中,我们可以给一个断点设置一个条件,之后就称为条件断点。

在cgdb中也可以, 条件断点添加的两种方式:

  1. 新增
  2. 给已有断点追加

5.1 新增条件断点

finish无法直接完成函数,而是停在条件断点处。

5.2 给条件断点新增条件 

使用condition给以有断点新增条件:

三、命令汇总 

刚才我们把所有的命令都讲解了一遍并也给出了图解,这里我们把所有的命令汇总一下。

  • list(或l) 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • list(或l) 函数名:列出某个函数的源代码。 r或run:运行程序。
  • n 或 next:单条执行。
  • s或step:进入函数调用
  • break(或b) 行号:在某一行设置断点
  • break(或b) 函数名:在某个函数开头设置断点
  • info(或i) break(或b) :查看断点信息。
  • finish:执行到当前函数返回,然后挺下来等待命令
  • print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数 
  • p 变量:打印变量值。
  • set var:修改变量的值
  • continue(或c):从当前位置开始连续而非单步执行程序
  • run(或r):从开始连续而非单步执行程序
  • delete(或d) breakpoints:删除所有断点
  • delete(或d) breakpoints n:删除序号为n的断点
  • delete(或d) n:删除序号为n的断点
  • disable breakpoints:禁用所有断点
  • enable breakpoints:启用所有断点
  • info(或i) breakpoints:参看当前设置了哪些断点
  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值
  • undisplay 变量名:取消对先前设置的那些变量的跟踪
  • until X行号:执行至X行
  • breaktrace(或bt):查看各级函数调用及参数
  • info(或i) locals:查看当前栈帧局部变量的值(自动窗口)
  • watch 变量名:监视运行时会发生变化的值
  • quit(或q):退出gdb

总结: 

本篇命令较多,大多都是记忆成本,但是我们还是需要学会使用的。

大家都要加油学习,知识很多,但是要相信水滴石穿,聚沙成塔,最终会在顶峰相会!


http://www.kler.cn/a/561921.html

相关文章:

  • window平台上qtcreator上使用opencv报错
  • uniApp小程序保存canvas图片
  • JavaScript基础(函数及面向对象)
  • 网络安全入门|从防护到溯源:HTTP慢速攻击的深度对抗
  • 警惕将“数据标注”岗位包装为“大数据工程师”充数
  • 电子商务网站租用香港服务器的好处有哪些?
  • Lab14_ Blind SQL injection with time delays
  • 【三维分割】LangSplat: 3D Language Gaussian Splatting(CVPR 2024 highlight)
  • 从零开始玩转TensorFlow:小明的机器学习故事 6
  • 每日精讲:删除有序数组中的重复项,移除元素,合并两个有序数组
  • 【Viewer.js】vue3封装图片查看器
  • 短剧源码部署搭建小程序搭建IAA+IAP混合解锁模式
  • 上海创智学院(测试)算法笔试(ACM赛制)部分例题
  • k8s集群3主5从高可用架构(kubeadm方式安装k8s)
  • 广州4399游戏25届春招游戏策划管培生内推
  • Linux搜索查找类指令
  • 【透视图像目标检测(3)】透视3D目标的航向角、观察角(局部方向)和相对位置角辨析,观察角的单目投影验证
  • 爬虫基础知识
  • 解析Excel表表头
  • 鸿蒙NEXT开发-用户通知服务