1. GDB入门

1.1 GDB到底是什么?

GDB,全称GNU Debugger。说白了,就是一个让你能「看穿」程序运行过程的工具。

我刚开始接触GDB时,觉得它就是个黑乎乎的终端工具。远不如IDE里点几下鼠标来得方便。但后来我遇到一个诡异的崩溃问题——程序在Release模式下跑得好好的,Debug模式下却时不时崩溃。IDE的调试器根本抓不住规律。最后是GDB帮我定位到了问题:一个未初始化的成员变量。

从那以后,我对GDB的看法彻底变了。

GDB能做什么?简单来说:

  • 让你在任意位置暂停程序(断点)
  • 查看变量、内存、寄存器的值
  • 单步执行,观察每一行代码的效果
  • 修改程序状态,测试不同场景
  • 分析崩溃现场(core dump)

嗯,这些功能IDE调试器也都有。但GDB有一个杀手锏——它不依赖图形界面。这意味着你可以在服务器上、在嵌入式设备上、在没有显示器的环境里调试程序。这一点,我在远程调试Qt程序时深有体会。

1.2 GDB与Qt的关系

Qt程序本质上就是C++程序。所以GDB能调试C++程序,自然也能调试Qt程序。

但这里有个坑——Qt程序用了很多宏、信号槽、元对象系统。这些东西在编译后会被展开成复杂的代码。如果你直接用GDB调试,看到的可能是moc生成的文件,而不是你写的代码。

我个人习惯的做法是:

  • 编译时加上 -g 选项,保留调试符号
  • 不要使用 -O2 或更高优化级别,否则变量可能被优化掉
  • 对于Qt项目,建议使用 qmake CONFIG+=debug 或CMake的 Debug 配置

举个例子,你在Qt里写了一个信号槽连接:

connect(button, &QPushButton::clicked, this, &MyClass::onClicked);

在GDB里,你看到的可能是:

QMetaObject::Connection QObject::connect(const QObject *, const char *,
                                          const QObject *, const char *,
                                          Qt::ConnectionType)

是不是有点懵?别担心,后面我会专门讲怎么在GDB里处理Qt的元对象系统。

我的经验:调试Qt程序时,建议同时开启Qt的调试输出。在main函数里加一句 qSetMessagePattern("[%{file}:%{line}] %{message}"),这样GDB配合日志,定位问题会快很多。

1.3 GDB的安装

安装GDB其实很简单。不同系统略有差异,我列个表方便你对照:

操作系统 安装命令 备注
Ubuntu/Debian sudo apt install gdb 一般系统自带,版本较新
CentOS/RHEL sudo yum install gdb 可能需要启用EPEL源
macOS brew install gdb 需要签名,否则无法调试
Windows MinGW或MSYS2自带 推荐使用Qt自带的MinGW

安装完成后,在终端输入 gdb --version,看到版本信息就说明装好了。

注意:macOS上安装GDB后,需要执行 codesign 签名才能正常使用。我曾经在这上面折腾了半天,后来发现直接用 lldb 反而更省事。如果你在macOS上开发Qt,也可以考虑用LLDB,命令和GDB基本兼容。

1.4 启动GDB的几种方式

启动GDB的方式有好几种,我根据场景不同会选择不同的方式:

方式一:直接调试可执行文件

gdb ./my_qt_app

这是最常用的方式。启动后,GDB会加载程序,但不会立即运行。你可以先设置断点,然后输入 run 启动。

方式二:调试正在运行的程序

gdb -p 12345   # 12345是进程ID

这个场景我遇到过好几次——程序跑起来后卡住了,或者CPU飙到100%。这时候用 -p 附加到进程,就能看到它在干什么。

方式三:分析core dump文件

gdb ./my_qt_app core.12345

程序崩溃后,如果生成了core dump文件,用这种方式可以查看崩溃时的现场。我个人强烈建议在开发环境开启core dump:

ulimit -c unlimited   # 取消core文件大小限制

方式四:Qt Creator集成

其实Qt Creator底层用的就是GDB。你在IDE里点「调试」按钮时,背后就是GDB在工作。但有时候IDE会隐藏一些细节,比如某些变量值被优化掉了,IDE显示「optimized out」,这时候切换到终端用GDB,反而能看到更多信息。

核心要点:GDB是Qt调试的基石。不管你是用Qt Creator、VS Code还是CLion,底层调试器大概率就是GDB。学会GDB,就等于掌握了调试的「底层原理」。

1.5 本章知识体系

下面这张图帮你梳理本章的核心内容:

GDB入门 GDB是什么 • 暂停程序、查看变量 • 单步执行、修改状态 • 分析崩溃现场 GDB与Qt的关系 • Qt程序本质是C++ • 信号槽展开后复杂 • 需保留调试符号 安装与启动 • apt/yum/brew安装 • 直接调试可执行文件 • 附加到运行进程 • 分析core dump GDB是Qt调试的底层工具,掌握它等于掌握调试的「底层原理」

这张图把本章的三个核心内容串起来了。GDB是什么解决「是什么」的问题,GDB与Qt的关系解决「为什么重要」的问题,安装与启动解决「怎么用」的问题。三者缺一不可。

避坑指南:我曾经在CentOS上遇到过GDB版本太旧,不支持某些新特性(比如Python扩展)。建议安装GDB 10.0以上版本。可以用 gdb --version 查看版本号,如果太低,考虑从源码编译安装。