【Linux】调试器gdb/cgdb的使用

发布于:2025-08-07 ⋅ 阅读:(15) ⋅ 点赞:(0)

        Linux下我们编译好的代码是无法直接进行调试的,gcc/g++的默认工作模式是release模式,gdb是一个调试器,本篇将介绍一下它的使用。

1.快速认识gdb

要使⽤gdb调试,必须在源代码⽣成⼆进制程序的时候(编译时), 加上 -g 选项,让生成的可执行程序添加调试信息,也可就是让代码处于debug模式
  •  readelf -S 可执行程序 | grep -i debug:查看可执行程序是有debug信息
我们的Makefile可以完善一下。
//Makefile文件
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
BIN=mycode

$(BIN):$(OBJ)
    gcc -o $@ $^
%.o:%.c
    gcc -c $< -g  #加上-g选项

.PHONY:clean
clean:
    rm -f $(OBJ) $(BIN)
  • gdb 可执行文件:进入gdb,gdb后面跟的是可执行程序,不是源文件!
  • quit:退出gdb

2.解决gdb难用问题

我们直接使用cgdb,用命令安装

Ubuntu环境:sudo apt-get install cgdb

安装好之后我们再打开cgdb。

cgdb有分屏,是上面是代码屏,下面是调试信息屏,它的界面就清楚很多。

  • 按ESC可以进入代码屏,但是可能会卡死!
  • 如果不小心导致页面卡死了,按i光标就能回退到下面调试信息处。

3.gdb/cgdb相关指令

cgdb的指令和gdb的指令是一样的,下面我就用cgdb演示,演示的代码如下:

#include <stdio.h>
int Sum(int s, int e)
{
    int result = 0;
    for(int i = s; i <= e; i++)
    {
        result += i;
    }
    return result;
}
int main()
{
    int start = 1;
    int end = 100;
    printf("begin...\n");
    int n = Sum(start, end);
    printf("running done, result is: [%d-%d]=%d\n", start, end, n);
    return 0;
}

3.1 常见使用

  • l:list,查看源代码,按回车就会往后显示,每次显示10行
  • r:run,从头运行,会在遇到的第一个断点处停下来,没有断点就直接运行到结束

在gdb中会记录最新的那条指令,只要按回车就会执行最新的那条语句

3.1.1 断点

  • b n:break,在第n行打断点
  • b 函数名:在指定的函数入口处打断点
  • b 文件名:n:在指定文件的第n行打断点
  • b 文件名:函数名:在指定文件的指定函数入口处打断点
  • info b:查看所有断点

  • d 断点编号delete,删除断点
  • disable 断点编号:禁用断点,此断点仍存在
  • enable 断点编号:启用断点
  • ccontinue,运行到下一个断点

gdb不退出,断点编号依次递增

3.1.2 语句

  • n:next,逐过程
  • s:step,逐语句
  • finish:执⾏到当前函数返回然后停⽌
  • btbacktrace,查看当前执⾏的各级函数调⽤及参数
  • until n:执行到指定行

3.1.3 变量

  • p 变量名:查看指定的变量名,不能常显
  • p 表达式:可以查看一个表达式的值
  • display 变量名:跟踪显⽰指定变量的值,常显示

  • undisplay 变量名编号:取消跟踪显⽰指定变量

  • info locals:查看一个函数里所有的变量

3.2 常见技巧

3.2.1 watch

  • watch 变量或表达式:监视一个变量或表达式,如果这个变量或表达式在运行期间发生了变化,gdb会暂停运行并通知使用者,不会常显,有变化才会显示

比如说我们监视这个result变量,watch result之后会有一个watchpoint的断点,用指令info b就能查看这个断点类型和监视的对象

当程序往后执行,检测到这个变量的变化后就会显示出来,并且这个watch可以对这个变量进行新旧的对比

如果不想要这个断点,就用 d 断点编号 进行删除

常见应用场景:如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你。

3.2.2 set var

  • set var 变量=新的值:我们在调试期间修改这个变量的值变成新的值,就不用退出gdb修改源代码来确定问题
比如这个求和函数,result的初始值应该是0,这里故意设置成1,设置成错的。
int Sum(int s, int e)
{
    //int result = 0;
    int result = 1; //设置错误
    for(int i = s; i <= e; i++)
    {
        result += i;
    }
    return result;
}

在我们调试的时候发现这个地方写错了,可直接用set var result=0进行值的暂时修改

但是这个操作不会修改源代码,发现问题知道错在哪后,还是要对源代码修改。

3.2.3 条件断点

  • b n if 条件:当条件成立的时候在第n行设置断点

比如在求和函数循环体内,当i为20的时候打个断点。

  • condition 断点编号 条件:给已存在的断点添加条件,断点已存在不用加if

注意两者的语法有区别,不要写错了!

这个断点可以搭配指令c一起用,我们刚刚打了一个条件断点,当i==20时触发断点,按c就会直接跳到这个地方

本次分享就到这里了,我们下篇再见~


网站公告

今日签到

点亮在社区的每一天
去签到