欢迎光临
我们一直在努力

Re : Linux 系统篇(九):开发工具 Chapter5 —— GDB 调试器从入门到精通【断点、单步、监视点与条件断点全解】

在这里插入图片描述

观众老爷们大家好 这里是邪修KING的独家频道

本文属于系列Linux系统篇 ——操作指令

一起学Linux的小伙伴可订阅专栏: Linux系统篇

前面我们掌握了 vim 写代码、gcc 编译、Makefile 构建,完成了从源码到可执行程序的完整流程。但写代码不可能没有 Bug,靠 printf 到处打日志排查不仅低效,还会污染代码。

GDB 就是 Linux 下最主流的命令行调试工具,可以设置断点、单步执行、查看变量、监视内存,是定位问题的神兵利器。本篇我们从 Debug 模式原理讲起,系统覆盖 GDB 全部核心命令,再深入监视点、条件断点、动态修改变量等高级技巧,带你彻底掌握命令行调试能力。

一、前置认知:Debug 与 Release 模式

1.1 两种程序发布模式

程序编译生成二进制时,通常有两种发布模式:

  • Release 模式:默认模式。会对代码进行各种优化(指令重排、变量优化、去除调试信息),程序体积小、运行快,但无法调试。
  • Debug 模式:不做优化,并且会在二进制文件中加入调试符号信息(行号、变量名、函数名映射),支持源码级调试。

gcc/g++ 默认生成的就是 Release 版本;想要用 GDB 调试,必须在编译时加上 -g 选项。

1.2 -g 调试选项

不加 -g 的程序,GDB 无法识别源码行号和变量,根本没法正常调试。

# 默认 release 模式,不支持调试
gcc mycmd.c -o mycmd

# debug 模式,加入调试信息,支持 gdb 调试
gcc mycmd.c -o mycmd -g

### 1.3 验证是否带调试信息

用 file 命令可以查看可执行文件的属性,判断是否包含调试信息:

file mycmd

  • 普通 Release 版本:显示 not stripped,但没有 debug_info 字样
  • Debug 版本(加了 -g):显示 with debug_info, not stripped,说明携带调试符号

二、GDB 与 CGDB 的区别

很多初学者容易混淆二者,这里先讲清楚定位差异: 在这里插入图片描述

简单说:CGDB = GDB + 实时代码显示窗口,操作命令和 GDB 完全一致,只是多了代码视图,调试更直观。

安装方法

# Ubuntu 安装
sudo apt install -y gdb
sudo apt install -y cgdb

# CentOS 安装
sudo yum install -y gdb
sudo yum install -y cgdb

三、调试示例代码准备

本篇所有调试操作,都基于下面这段示例代码 mycmd.c:

#include <stdio.h>

int flag = 0; // 用于演示 set var 调试

int Sum(int s, int e)
{
int result = 0;
for(int i = s; 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;
}

编译生成 Debug 版本:

gcc mycmd.c -o mycmd -g

四、GDB 核心命令全解

4.1 启动与退出

启动调试

# 直接加载可执行文件进入 gdb
gdb mycmd

进入后会显示 (gdb) 提示符,所有调试命令都在这里输入。

退出 GDB

# 方式1:输入 quit 命令
quit
# 方式2:快捷键 Ctrl + d

4.2 查看源代码:list /l

程序跑起来之前,可以先查看源码,确认行号方便打断点。 在这里插入图片描述

4.3 运行程序:run /r

run
# 简写 r

从程序入口开始全速执行,直到遇到断点或者程序结束。

  • 如果程序需要传参:r 参数1 参数2

4.4 断点管理:break /b

断点是调试的核心,让程序运行到指定位置停下来。

设置断点

在这里插入图片描述

查看断点

info break
# 简写 i b

会列出所有断点的编号、类型、位置、启用状态等信息,每个断点都有一个唯一编号。

删除断点

# 删除所有断点
delete breakpoints

# 删除指定编号的断点,比如删除 2 号断点
delete breakpoints 2
# 简写 d 2

禁用 / 启用断点

不想删但暂时不想让它生效,可以禁用:

# 禁用所有断点
disable breakpoints

# 启用所有断点
enable breakpoints

4.5 单步调试

程序在断点停下后,就可以一步步控制执行了 在这里插入图片描述 最常用的组合:

  • 想快速过掉函数调用 → n
  • 想进入函数内部排查 → s
  • 进了函数想直接出来 → finish
  • 想跑到下一个断点 → c

4.6 变量查看与修改

程序停下后,可以查看和修改任意变量的值。

打印变量

# 打印变量/表达式的值
print 变量名
# 简写 p 变量名

# 示例
p result
p start + end

查看所有局部变量

info locals

一次性打印当前栈帧所有局部变量的值,快速排查。

动态修改变量

调试时不用改代码重编译,直接在 GDB 里改内存里的值,用来验证猜想非常方便

set var 变量=

# 示例:把 flag 改成 1
set var flag=1

这是定位问题的神器:怀疑某个变量导致异常,直接改值继续跑,立刻验证判断对不对。

4.7 查看调用栈:backtrace /bt

backtrace
# 简写 bt

打印当前的函数调用栈,能看到各级函数的调用关系和参数,适合排查程序崩溃、异常嵌套调用的场景。


五、高级调试技巧

5.1 watch 监视点:揪出变量的意外修改

什么是监视点

watch 可以监视一个变量或表达式,只要它的值发生变化,程序就会立刻停下,并告诉你旧值和新值。

非常适合这种场景:

某个变量莫名其妙被改了,但不知道是哪行代码改的。用 watch 盯着它,一改就断住,直接定位凶手。

使用示例

# 1. 先进入 Sum 函数,让 result 变量存在
b Sum
r
s

# 2. 设置监视点,盯着 result 变量
watch result
# 提示:Hardware watchpoint 2: result

# 3. 继续运行
c

每次 result 值变化,程序都会自动停下,打印:

Hardware watchpoint 2: result
Old value = 0
New value = 1
Sum (s=1, e=100) at mycmd.c:7

精准定位到修改变量的那一行代码。

注意:watch 是硬件级监视点,效率很高;只能监视当前已经存在的变量,变量销毁后监视点自动失效。

5.2 set var 实战:定位 flag 导致的异常

我们用示例代码演示一个真实排查场景: 程序运行结果是 0,但 1 加到 100 应该是 5050,为什么变成 0 了?

排查步骤

  • 在 Sum 函数返回前打断点
  • b 16
    r

    2.程序停下后,打印 result 和 flag

    p result # 输出 5050,计算是对的
    p flag # 输出 0,原来 flag 是 0!

    3.怀疑是 flag 乘进去导致结果为 0,验证一下

    set var flag=1 # 动态把 flag 改成 1
    p flag # 确认变成 1
    n # 继续执行返回

    4.4. 回到 main 后看结果,变成了 5050,确认就是 flag=0 导致的问题。

    整个过程不用改代码、不用重新编译,几分钟就能定位根因,这就是调试器的价值。

    5.3 条件断点:只在满足条件时停下

    普通断点每次到那行都停,循环里打断点会停几十上百次,非常麻烦。条件断点可以设置触发条件,只有条件满足时才停下。

    两种设置方式

    方式 1:新增断点时直接加条件

    # 在第9行打断点,只有 i 等于 30 时才停下
    b 9 if i == 30

    方式 2:给已有断点追加条件

    # 先看断点编号,比如 2 号断点在 Sum 第9行
    info b

    # 给 2 号断点追加条件 i==30
    condition 2 i==30

    语法区别:

    • 新增时:b 行号 if 条件
    • 追加时:condition 断点号 条件(没有 if)

    效果

    循环 100 次,普通断点会停 100 次;加了 i==30 的条件断点,只在 i 等于 30 那一次停下,直接跳到你关心的状态,效率提升巨大。


    六、CGDB 快速上手

    GDB 功能很强,但每次看代码都要敲 l,很不方便。CGDB 在 GDB 基础上加了源码分屏,体验好很多。

    启动

    cgdb mycmd

    默认上半屏是代码窗口,高亮显示当前执行行;下半屏是 GDB 命令窗口,命令和 GDB 完全一样。

    窗口切换

    • 按 ESC:焦点切到代码窗口,可以用方向键、PageUp/PageDown 翻代码
    • 按 i:焦点切回 GDB 命令窗口,继续输入调试命令

    其他所有调试命令和 GDB 完全通用,不用重新学习。


    七、调试流程建议 & 命令速查

    7.1 常规调试步骤

  • 编译加 -g 生成 Debug 版本
  • gdb 程序名 启动调试
  • 在关键位置打 break 断点
  • run 运行到断点处
  • n / s 单步跟踪,p 查看变量
  • 定位问题后,set var 验证猜想
  • continue 继续运行,quit 退出
  • 7.2 高频命令速查表

    在这里插入图片描述

    本篇总结

    调试能力是开发者的核心竞争力,printf 调优只能应付小问题,面对复杂项目、偶现 Bug、变量异常修改等场景,专业调试器才是高效解决方案。

    • 基础:掌握断点、单步、查看变量,就能解决 80% 的调试问题
    • 进阶:watch 监视点、set var 动态改值、条件断点,能大幅提升复杂问题的排查效率
    • 体验:纯命令用 GDB,想看源码上下文用 CGDB,二者命令完全兼容

    到这里,Linux 下「编辑 → 编译 → 构建 → 调试」的完整开发工具链就全部讲完了。下一篇我们将深入程序链接阶段,讲解动态库与静态库的原理、制作与使用,彻底搞懂程序从源码到运行的最后一块拼图。

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » Re : Linux 系统篇(九):开发工具 Chapter5 —— GDB 调试器从入门到精通【断点、单步、监视点与条件断点全解】
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址