【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 编号 条件

相关推荐
luoganttcc4 小时前
介绍一下 multiprocessing 的 Manager模块
linux·运维·服务器
阿巴~阿巴~4 小时前
线程互斥:并发编程中的互斥量(Mutex)与RAII风格锁管理机制
linux·线程·pthread·互斥量·线程互斥·线程封装·raii原则
牛奶咖啡135 小时前
Linux中安装部署Hadoop集群的保姆级安装配置教程
linux·hadoop·openjdk21安装配置·openjre21安装配置·hadoop集群安装配置·linux的ssh配置·linux实现免密登录配置
dessler5 小时前
MYSQL-数据库介绍
linux·运维·mysql
Garc6 小时前
linux Debian 12 安装 Docker(手动)
linux·docker·debian
kaoa0006 小时前
Linux入门攻坚——52、drbd - Distribute Replicated Block Device,分布式复制块设备-1
linux·运维·服务器
Kay_Liang6 小时前
【Hive 踩坑实录】从元数据库初始化到 HiveServer2 启动的全流程问题解决
大数据·linux·hive·hadoop·笔记·mysql·ubuntu
NiKo_W6 小时前
Linux Socket网络编程基础
linux·服务器·网络
啊略略wxx7 小时前
嵌入式Linux面试题目
linux·运维·服务器