【Linux指南】Linux调试利器gdb入门:从编译到基础命令实战

一、引言:为什么gdb是Linux开发者的必备技能?

在Linux环境下开发C/C++程序时,遇到bug是家常便饭。无论是逻辑错误、内存泄漏还是运行时崩溃,一款强大的调试工具都能帮我们快速定位问题根源。gdb(GNU Debugger) 作为Linux系统中最常用的命令行调试工具,支持断点设置、变量查看、单步执行等核心功能,是开发者排查问题的"利器"。

本文将从最基础的"如何生成可调试程序"讲起,逐步介绍gdb的启动方式、核心调试命令及实战技巧,帮助新手快速掌握gdb的使用方法。

@[toc]

二、前提:生成可调试的程序

2.1 程序的两种发布模式

Linux下用gcc/g++编译的程序有两种发布模式,调试前必须了解两者的区别:

  • release模式:默认编译模式,生成的二进制文件体积小、运行效率高,但不包含调试信息(如行号、变量类型等),无法用gdb调试。
  • debug模式 :需在编译时添加-g选项,会在二进制文件中嵌入调试信息,供gdb识别。只有这种模式的程序才能被gdb调试。

2.2 实战:编译可调试程序

以一个简单的C程序test.c为例:

c 复制代码
#include <stdio.h>
int main() {
    int sum = 0;
    for (int i = 1; i <= 5; i++) {
        sum += i;
    }
    printf("sum = %d\n", sum);
    return 0;
}

编译生成可调试文件的命令:

bash 复制代码
gcc -g test.c -o test  # 关键:-g选项必须添加,否则无法调试

若未加-g选项,使用gdb调试时会提示无法识别调试信息,导致无法正常调试。

三、gdb基础操作:启动与退出

3.1 启动gdb

gdb只能调试**二进制文件**(编译后的可执行程序),不能直接调试源文件。 启动命令格式:

bash 复制代码
gdb 二进制文件名

示例:调试上面生成的test程序

bash 复制代码
gdb test

执行后会进入gdb调试界面,显示版本信息及命令提示:

scss 复制代码
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7
Copyright (C) 2013 Free Software Foundation, Inc.
...
(gdb)  # 命令输入提示符

3.2 退出gdb

退出调试界面有两种方式:

  • 输入quit命令并回车
  • 按下Ctrl + d组合键

四、查看源代码:list命令详解

在调试过程中,我们需要随时查看源代码以确定调试位置。gdb的list(缩写l)命令用于显示源代码,支持多种灵活用法。

4.1 基本用法

  • list(或l):默认从当前位置显示10行源代码,多次执行会继续显示后续内容。
  • list 行号(如l 5):显示指定行号附近的代码(以该行号为中心,显示前后内容)。
  • list 函数名(如l main):显示指定函数的源代码,方便快速定位函数入口。
  • list 文件名:行号(如l test.c:8):当调试多文件项目时,可指定文件名和行号查看代码。

4.2 示例

test程序的gdb界面中执行:

bash 复制代码
(gdb) l main  # 查看main函数代码
1       #include <stdio.h>
2       int main() {
3           int sum = 0;
4           for (int i = 1; i <= 5; i++) {
5               sum += i;
6           }
7           printf("sum = %d\n", sum);
8           return 0;
9       }

五、程序运行控制:从启动到单步执行

掌握程序运行的控制命令是调试的核心,gdb提供了丰富的命令用于控制程序执行流程。

5.1 启动程序:run命令

  • 命令:run(缩写r
  • 功能:启动程序运行,若程序有断点,会在第一个断点处暂停;若无断点,程序会直接运行结束。
  • 示例:
bash 复制代码
(gdb) r  # 启动test程序
Starting program: /home/user/test 
sum = 15
[Inferior 1 (process 12345) exited normally]

5.2 单步执行:next与step

单步执行用于逐行检查代码执行过程,两者的区别在于是否进入函数内部:

  • next(缩写n):单步执行,不进入函数内部(适合跳过无关函数,关注当前逻辑)。
  • step(缩写s):单步执行,进入函数内部(适合调试函数调用时的逻辑)。

5.3 结束当前函数:finish命令

  • 命令:finish
  • 功能:当进入函数内部调试时,执行该命令可直接运行到函数返回处并暂停,适合快速跳出无关函数。
  • 示例:若在sum += i处单步进入了某个函数,执行finish可直接回到循环逻辑。

5.4 继续运行:continue命令

  • 命令:continue(缩写c
  • 功能:从当前暂停位置继续运行程序,直到遇到下一个断点或程序结束。
  • 场景:常用于多个断点之间的跳转,避免重复单步执行。

六、变量与表达式操作:查看与修改

调试的核心目的之一是观察变量值的变化,gdb提供了多种命令用于操作变量和表达式。

6.1 打印变量/表达式值:print命令

  • 命令:print(缩写p
  • 功能:打印变量值或表达式计算结果。
  • 示例:
bash 复制代码
(gdb) p sum  # 打印变量sum的值
$1 = 0
(gdb) p i  # 打印变量i的值
$2 = 1
(gdb) p sum + i  # 计算表达式结果
$3 = 1

6.2 修改变量值:set var命令

  • 命令:set var 变量名=值
  • 功能:直接修改程序中变量的值,无需重新编译即可测试不同场景(如强制跳过错误分支)。
  • 示例:
bash 复制代码
(gdb) set var i=5  # 将i的值改为5,强制循环提前结束
(gdb) p i
$4 = 5

6.3 跟踪变量:display命令

  • 命令:display 变量名
  • 功能:设置变量跟踪,程序每次暂停时会自动打印该变量的值,无需反复输入print
  • 示例:
bash 复制代码
(gdb) display sum  # 跟踪sum的值
1: sum = 0
(gdb) n  # 单步执行后自动显示sum
4           for (int i = 1; i <= 5; i++) {
1: sum = 0
(gdb) n
5               sum += i;
1: sum = 0
(gdb) n
4           for (int i = 1; i <= 5; i++) {
1: sum = 1

6.4 取消跟踪:undisplay命令

  • 命令:undisplay 编号(编号可通过display命令的输出查看,如上述示例中的1
  • 功能:取消对指定变量的跟踪显示。
  • 示例:
bash 复制代码
(gdb) undisplay 1  # 取消对sum的跟踪

七、断点管理:精准控制暂停位置

断点是调试中最常用的功能,用于在指定位置暂停程序,以便观察状态。

7.1 设置断点:break命令

  • 命令:break(缩写b

  • 功能:在指定行号、函数或文件中设置断点。

  • 常用用法:

    • b 行号(如b 5):在当前文件第5行设置断点。
    • b 函数名(如b main):在函数入口处设置断点。
    • b 文件名:行号(如b test.c:5):在指定文件的指定行设置断点。
  • 示例:在test.c第5行(sum += i)设置断点:

bash 复制代码
(gdb) b test.c:5
Breakpoint 1 at 0x400526: file test.c, line 5.

7.2 查看断点:info break命令

  • 命令:info break(缩写info b
  • 功能:显示当前所有断点的信息,包括编号、位置、状态等。
  • 示例:
bash 复制代码
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400526 in main at test.c:5

7.3 删除断点:delete命令

  • 命令:delete(缩写d
  • 功能:删除断点,支持删除单个或所有断点。
  • 用法:
    • delete 断点编号(如delete 1):删除指定编号的断点。
    • delete breakpoints:删除所有断点。

7.4 禁用/启用断点:disable与enable

  • disable 断点编号:临时禁用断点(断点仍存在,不触发暂停)。
  • enable 断点编号:重新启用被禁用的断点。
  • 场景:暂时不需要某个断点但不想删除时使用。

八、实战案例:调试一个简单程序

下面通过调试test.c演示完整流程:

  1. 编译可调试程序
bash 复制代码
gcc -g test.c -o test
  1. 启动gdb
bash 复制代码
gdb test
  1. 设置断点 :在循环的sum += i处(第5行)设置断点:
bash 复制代码
(gdb) b test.c:5
Breakpoint 1 at 0x400526: file test.c, line 5.
  1. 启动程序
bash 复制代码
(gdb) r
Starting program: /home/user/test 

Breakpoint 1, main () at test.c:5
5               sum += i;
  1. 单步执行并观察变量
bash 复制代码
(gdb) n  # 执行sum += i
6           }
(gdb) p sum  # 此时sum=1
$1 = 1
(gdb) n  # 进入下一次循环
5               sum += i;
(gdb) p i  # 此时i=2
$2 = 2
(gdb) p sum  # 执行sum += i前,sum=1
$3 = 1
(gdb) n  # 再次执行sum += i
6           }
(gdb) p sum  # 此时sum=3
$4 = 3
  1. 继续运行到结束
bash 复制代码
(gdb) c  # 继续执行
Continuing.
sum = 15
[Inferior 1 (process 12345) exited normally]
  1. 退出gdb
bash 复制代码
(gdb) quit

九、总结:必备命令速查表

命令用途 命令(全称/缩写) 示例
启动gdb gdb 二进制文件 gdb test
退出gdb quit / Ctrl+d quit
查看源代码 list / l 行号/函数名 l 5、l main
启动程序 run / r r
单步执行(不进函数) next / n n
单步执行(进函数) step / s s
继续运行 continue / c c
设置断点 break / b 位置 b 5、b main
查看断点 info break / info b info b
删除断点 delete 编号 / delete breakpoints delete 1、delete breakpoints
打印变量 print / p 变量/表达式 p sum、p sum+i
修改变量 set var 变量=值 set var i=5

通过本文的学习,你已经掌握了gdb的基础用法。下一篇将介绍gdb的进阶技巧,包括条件断点、变量跟踪等高级功能,帮助你更高效地调试复杂程序。

相关推荐
CZZDg6 小时前
kubectl-etcd
linux·数据库·etcd
倔强的石头_6 小时前
【Linux指南】gdb进阶技巧:断点高级玩法与变量跟踪实战
linux
半桔6 小时前
【Linux手册】Unix/Linux 信号:原理、触发与响应机制实战
linux·运维·unix·信号处理
半梦半醒*6 小时前
ansible常用命令的简单练习
linux·运维·服务器·ansible·运维开发
小晶晶京京7 小时前
day42-Ansible
linux·运维·服务器·ansible
正在努力的小河7 小时前
Linux按键输入实验
linux·运维·服务器
币圈小菜鸟7 小时前
Selenium 自动化测试实战:绕过登录直接获取 Cookie
linux·python·selenium·测试工具·ubuntu·自动化
凌肖战7 小时前
Linux下usb设备驱动框架实现:定义核心结构体数据
linux·驱动开发
半梦半醒*8 小时前
ansible的playbook练习题
linux·运维·服务器·ssh·ansible·运维开发