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

相关推荐
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩3 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言