【Linux系统编程】调试器-gdb/cgdb

【Linux系统编程】调试器-gdb/cgdb

  • [1. Debug和Release](#1. Debug和Release)
  • [2. gdb/cgdb基本命令和使用](#2. gdb/cgdb基本命令和使用)
    • [2.1 list/l 命令](#2.1 list/l 命令)
    • [2.2 break/b、info break/b、delete/d breakpoints](#2.2 break/b、info break/b、delete/d breakpoints)
    • [2.3 r/run、n/next、s/step](#2.3 r/run、n/next、s/step)
    • [2.4 print/p、display、undisplay、until](#2.4 print/p、display、undisplay、until)
    • [2.5 finish、continue/c](#2.5 finish、continue/c)
    • [2.6 disable breakpoints、 enable breakpoints](#2.6 disable breakpoints、 enable breakpoints)
    • [2.7 set var](#2.7 set var)
    • [2.8 watch](#2.8 watch)
    • [2.9 条件断点](#2.9 条件断点)

1. Debug和Release

gdb/cgdb是一个强大的调试工具,支持多种编程语言,主要用于C/C++程序调试。

我们以下面的代码为例去认识gdb/cgdb。

cpp 复制代码
// mycmd.c
#include <stdio.h>

//int flag = 0; // 故意错误
//int flag = -1;
int flag = 1;

int Sum(int s, int e)
{
    int result = 0;
    int i = s;
    for(; i <= e; i++)
    {
        result += i;
    }
    return result * flag;
}

int main()
{
    int start = 1;
    int end = 100;
    printf("I will begin\n");
    int n = Sum(start, end);
    printf("running done, result is: [%d~%d]=%d\n", start, end, n);
    return 0;
}

我们用gcc去直接编译该代码生成的二进制程序是Release版本的。

我们用命令readelf -S mycmd | grep -i debug去检查可执行文件或目标文件(即mycmd)中是否包含调试信息,以及调试信息的详细情况。

发现mycmd中没有任何调试信息。

要想让gcc编译mycmd.c生成debug版本的二进制程序要加-g选项

gcc -g mycmd.c -o mycmd-debug

发现mycmd-debug确实有调试信息。

而且从文件大小也能看出mycmd-debug确实有调试信息。

既然gdb是调试器,那么分别对mycmd和mycmd-debug用gdb调试,也能看出来mycmd是没有调试信息的。

2. gdb/cgdb基本命令和使用

2.1 list/l 命令

list/l 行号 :显示源代码,从上次位置开始,每次列出10行

list/l 函数名 :列出指定函数的源代码

list/l ⽂件名:⾏号 :列出指定⽂件的源代码

quit:退出gdb

是不是感觉如果通过list查看行号,然后调试的话特别麻烦?

所以可以使用cgdb,cgdb和gdb的命令是完全一样的。不同的是cgdb可以直接看着代码去调试。


2.2 break/b、info break/b、delete/d breakpoints

break/b [文件名]:行号 :在指定⾏号设置断点

break/b 函数名 :在函数开头设置断点

info break/b :查看当前所有断点的信息

delete/d breakpoints :删除所有断点

delete/d breakpoints n :删除序号为n的断点

注意:删除时 n 指的是序号,不是行号

2.3 r/run、n/next、s/step

r/run :从程序开始连续执⾏

n/next :单步执⾏,不进⼊函数内部

s/step :单步执⾏,进⼊函数内部

2.4 print/p、display、undisplay、until

print/p 表达式 :打印表达式的值

p 变量 :打印指定变量的值

display 变量名 :跟踪显示指定变量的值(每次停⽌时)

undisplay 编号 :取消对指定编号的变量的跟踪显示

until 行号 执⾏到指定⾏号

什么命令也不输入直接执行,会执行上次输入的命令

2.5 finish、continue/c

finish :执⾏到当前函数返回,然后停⽌

continue/c :从当前位置开始连续执⾏程序

2.6 disable breakpoints、 enable breakpoints

disable breakpoints :禁用所有断点

enable breakpoints :启用所有断点

为什么不直接删除断点,而选择禁用断点,防止此次调试debug未彻底,以便以后再次debug。

2.7 set var

set var 变量=值 :修改变量的值

为了更好地演示,先把flag从1改成0

cpp 复制代码
// mycmd.c
#include <stdio.h>

int flag = 0; // 故意错误
//int flag = -1;
//int flag = 1;

int Sum(int s, int e)
{
    int result = 0;
    int i = s;
    for(; i <= e; i++)
    {
        result += i;
    }
    return result * flag;
}

int main()
{
    int start = 1;
    int end = 100;
    printf("I will begin\n");
    int n = Sum(start, end);
    printf("running done, result is: [%d~%d]=%d\n", start, end, n);
    return 0;
}

改完后发现1~100的和为0,假如我们不知道是flag导致的错误,此时我们要用cgdb进行调试。

我们调试到这里,发现是因为flag=0,导致的函数返回值为0,进而导致输出结果为0,我们如果结束调试把flag改为1再测试程序是否正确的话太慢了,所以可以用命令set var flag=1,在调试中让flag=1,观察结果是否正确,加快了调试效率。

发现结果正确,所以得出结论是因为flag错误而导致的程序结果错误。

2.8 watch

执行时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发⽣变化,GDB会暂停程序的执行,并通知使⽤者。

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

2.9 条件断点

添加条件断点

b 行号/文件名:行号/函数名 if 条件

给已经存在的断点新增条件

condition 编号 条件

相关推荐
倔强的石头1063 小时前
openGauss数据库:从CentOS 7.9部署到实战验证
linux·数据库·centos
梁正雄4 小时前
linux服务-Nginx+Tomcat+Redis之Session 共享 - 容器单机版
linux·nginx·tomcat
linchare7 小时前
linux debian上只装mysql的客户端步骤
linux·mysql·debian
百***75749 小时前
linux上redis升级
linux·运维·redis
顾安r9 小时前
11.22 脚本打包APP 排错指南
linux·服务器·开发语言·前端·flask
Neur0toxin9 小时前
入侵排查_2025/11/23
linux·windows·应急响应
小小编程能手10 小时前
Linux文件编程
linux·运维·服务器
木童66210 小时前
nginx安装步骤详解
linux·运维·服务器·网络·nginx
暴躁的菜鸡11 小时前
Ubuntu安装向日葵
linux·运维·ubuntu
wa的一声哭了11 小时前
Webase部署Webase-Web在合约IDE页面一直转圈
linux·运维·服务器·前端·python·区块链·ssh