Ubuntu 22.04 GDB 安装与命令参数详解
Ubuntu 22.04 下 GDB 12.1 在线/离线安装、全部命令行参数与交互调试命令详解,含完整调试会话与段错误定位实战。
Ubuntu 22.04 GDB 安装与命令参数详解
目标:在 Ubuntu 22.04 x86_64 环境完成 GDB 12.1 的从 0 到 1 安装(在线 + 离线两种方案),并逐一实测 GDB 的命令行参数与交互调试命令,最终演示一次完整的断点调试会话和一次段错误定位实战。本文所有命令与回显均为真实环境实测结果。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04 LTS(jammy) |
| 系统架构 | x86_64 |
| 内核版本 | 5.15.0(jammy 默认内核线) |
| 包管理器 | apt(dpkg) |
| 软件源 | archive.ubuntu.com / security.ubuntu.com 官方源 |
| GDB 版本 | GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1 |
| 编译器 | gcc 11.4.0(用于构建演示程序) |
二、工具概述
GDB(GNU Debugger,GNU 调试器)是 GNU 项目提供的源码级调试器,用于在程序运行时对其进行断点控制、单步跟踪、变量与内存查看、调用栈回溯,以及崩溃(段错误等)现场定位。GDB 支持 C、C++、D、Objective-C、Fortran、Java、OpenCL C、Pascal、汇编、Modula-2、Go 和 Ada 等多种语言。
GDB 与编译工具链中的其他成员配合工作:
- gcc/g++:负责编译,配合
-g选项生成调试符号表,GDB 才能做源码级调试; - make/cmake:负责构建工程,GDB 调试的是构建产出的可执行文件;
- valgrind:负责内存错误检测(越界、泄漏等),与 GDB 的"运行时断点 + 崩溃定位"互补,二者常配合排查疑难问题。
典型使用场景:
- 程序运行结果与预期不符,在关键函数入口设断点逐步查看中间变量;
- 程序崩溃(Segmentation fault),用 GDB 快速定位崩溃行与调用栈;
- 线上进程异常,用
gdb -p <pid>附加到运行中的进程现场分析; - 逆向或底层分析,用
disassemble、x/i $pc查看汇编指令。
三、在线安装方案
Ubuntu 的 apt 软件源中已经收录了 GDB,官方源即可安装,无需额外配置第三方源。
3.1 更新软件源索引
安装前先执行一次软件源更新,确保索引为最新:
sudo apt update
实测回显:
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Hit:1 http://security.ubuntu.com/ubuntu jammy-security InRelease
Hit:2 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Reading package lists...
Building dependency tree...
Reading state information...
8 packages can be upgraded. Run 'apt list --upgradable' to see them.
💡 说明:末尾的 "8 packages can be upgraded" 表示系统里有 8 个软件包存在新版本,属于正常提示,与本次安装 GDB 无关。
3.2 安装 GDB
sudo apt install -y gdb
实测回显(演示环境中 GDB 此前已安装,apt 直接提示已是最新版本):
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
gdb is already the newest version (12.1-0ubuntu1~22.04.2).
0 upgraded, 0 newly installed, 0 to remove and 8 not upgraded.
💡 说明:若在全新环境首次安装,回显会变为下载与安装过程,形如
Get:1 http://archive.ubuntu.com/ubuntu ... gdb ...与Setting up gdb ...,最终输出gdb is already the newest version之前会先完成实际安装。-y表示跳过确认提示,自动应答。
3.3 验证安装
查看版本:
gdb --version
实测回显:
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
查看帮助(关键片段):
gdb --help
实测回显(节选):
This is the GNU debugger. Usage:
gdb [options] [executable-file [core-file or process-id]]
gdb [options] --args executable-file [inferior-arguments ...]
Selection of debuggee and its files:
--args Arguments after executable-file are passed to inferior.
--core=COREFILE Analyze the core dump COREFILE.
--exec=EXECFILE Use EXECFILE as the executable.
--pid=PID Attach to running process PID.
--directory=DIR Search for source files in DIR.
--se=FILE Use FILE as symbol file and executable file.
--symbols=SYMFILE Read symbols from SYMFILE.
--readnow Fully read symbol files on first access.
--readnever Do not read symbol files.
--write Set writing into executable and core files.
Initial commands and command files:
--command=FILE, -x Execute GDB commands from FILE.
--init-command=FILE, -ix
Like -x but execute commands before loading inferior.
--eval-command=COMMAND, -ex
Execute a single GDB command.
May be used multiple times and in conjunction
with --command.
--init-eval-command=COMMAND, -iex
Like -ex but before loading inferior.
--nh Do not read ~/.gdbinit.
--nx Do not read any .gdbinit files in any directory.
Output and user interface control:
--fullname Output information used by emacs-GDB interface.
--interpreter=INTERP
Select a specific interpreter / user interface.
--tty=TTY Use TTY for input/output by the program being debugged.
-w Use the GUI interface.
--nw Do not use the GUI interface.
--tui Use a terminal user interface.
--dbx DBX compatibility mode.
-q, --quiet, --silent
Do not print version number on startup.
Operating modes:
--batch Exit after processing options.
--batch-silent Like --batch, but suppress all gdb stdout output.
--return-child-result
GDB exit code will be the child's exit code.
--configuration Print details about GDB configuration and then exit.
--help Print this message and then exit.
--version Print version information and then exit.
Remote debugging options:
-b BAUDRATE Set serial port baud rate used for remote debugging.
-l TIMEOUT Set timeout in seconds for remote debugging.
Other options:
--cd=DIR Change current directory to DIR.
--data-directory=DIR, -D
Set GDB's data-directory to DIR.
至此,GDB 在线安装完成。
四、离线安装方案
在无法访问互联网的内网环境,可提前在有网的机器上下载 GDB 的 .deb 安装包,拷贝到目标机器后用 dpkg -i 离线安装。
4.1 下载 GDB 安装包
sudo apt install --reinstall --download-only -y gdb
💡 说明:
--download-only只下载不安装;若目标软件包已安装,apt 默认不会再下载,此时加--reinstall可强制重新获取安装包。全新环境可直接用sudo apt install --download-only --no-install-recommends -y gdb,--no-install-recommends表示不下载推荐包,减小体积。
实测回显:
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 8 not upgraded.
Need to get 3920 kB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 gdb amd64 12.1-0ubuntu1~22.04.2 [3920 kB]
Fetched 3920 kB in 3s (1402 kB/s)
Download complete and in download only mode
下载的 .deb 包存放在 apt 缓存目录 /var/cache/apt/archives/ 下:
ls -lh /var/cache/apt/archives/gdb_*.deb
实测回显:
-rw-r--r-- 1 root root 3.8M Jun 20 2024 /var/cache/apt/archives/gdb_12.1-0ubuntu1~22.04.2_amd64.deb
💡 说明:GDB 的安装包名带架构后缀 amd64,对应 x86_64 架构。首次全新下载时,Depends 中的依赖包(libbabeltrace1、libdebuginfod1、libipt2、libsource-highlight4v5 等)也会一并下载到同一目录,拷包时需一并拷贝。
4.2 查看安装包信息
用 dpkg-deb -I 查看 .deb 包的元信息(包名、版本、架构、依赖等):
dpkg-deb -I /var/cache/apt/archives/gdb_12.1-0ubuntu1~22.04.2_amd64.deb
实测回显:
new Debian package, version 2.0.
size 3920084 bytes: control archive=2915 bytes.
17 bytes, 1 lines conffiles
1162 bytes, 21 lines control
5141 bytes, 71 lines md5sums
Package: gdb
Version: 12.1-0ubuntu1~22.04.2
Architecture: amd64
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Installed-Size: 11313
Depends: libbabeltrace1 (>= 1.5.4), libc6 (>= 2.34), libdebuginfod1 (>= 0.180), libexpat1 (>= 2.0.1), libgcc-s1 (>= 4.2), libgmp10 (>= 2:6.2.1+dfsg), libipt2 (>= 2.0), liblzma5 (>= 5.1.1alpha+20110809), libmpfr6 (>= 3.1.3), libncursesw6 (>= 6), libpython3.10 (>= 3.10.0), libreadline8 (>= 8), libsource-highlight4v5 (>= 3.1.9), libstdc++6 (>= 12), libtinfo6 (>= 6), libxxhash0 (>= 0.6.5), zlib1g (>= 1:1.2.0)
Recommends: libc-dbg
Suggests: gdb-doc, gdbserver
Conflicts: gdb
Replaces: gdb
Provides: gdb-minimal (= 12.1-0ubuntu1~22.04.2)
Section: devel
Priority: optional
Homepage: https://www.gnu.org/s/gdb/
Description: GNU Debugger
GDB is a source-level debugger, capable of breaking programs at
any specific line, displaying variable values, and determining
where errors occurred. Currently, gdb supports C, C++, D,
Objective-C, Fortran, Java, OpenCL C, Pascal, assembly, Modula-2,
Go, and Ada. A must-have for any serious programmer.
4.3 拷贝安装包到离线目录
建立离线安装目录并拷贝 .deb 包(同时将依赖包一并拷贝,此处演示环境依赖已装齐,仅需拷贝 gdb 本体):
sudo mkdir -p /opt/devchain-demo/gdb-ubuntu-test/offline
sudo cp /var/cache/apt/archives/gdb_*.deb /opt/devchain-demo/gdb-ubuntu-test/offline/
确认拷贝结果:
ls -lh /opt/devchain-demo/gdb-ubuntu-test/offline/
实测回显:
total 3.8M
-rw-r--r-- 1 root root 3.8M Oct 6 06:35 gdb_12.1-0ubuntu1~22.04.2_amd64.deb
4.4 离线安装
在目标机器(无外网)上执行:
sudo dpkg -i /opt/devchain-demo/gdb-ubuntu-test/offline/gdb_*.deb
⚠️ 注意:若目标机器缺少 Depends 中的依赖包,
dpkg -i会提示依赖未满足;此时需将依赖包也拷贝到同目录一并安装(内网可用离线源:sudo apt install ./gdb_*.deb命令可同时解析同目录下的依赖包)。安装完成后用gdb --version验证。
五、命令与参数详解
演示程序:先准备两个带调试信息的 C 程序用于演示。创建测试目录,编写 debugme.c(正常程序)与 bug.c(带缺陷程序):
mkdir -p /opt/devchain-demo/gdb-ubuntu-test
debugme.c 内容(含函数 add、局部变量、if/for 循环、数组):
#include <stdio.h>
int add(int a, int b) {
int sum = a + b;
return sum;
}
int main() {
int x = 10;
int y = 20;
int arr[5] = {1, 2, 3, 4, 5};
int i;
for (i = 0; i < 5; i++) {
arr[i] = arr[i] * 2;
}
if (x > 5) {
y = add(x, y);
}
printf("y = %d\n", y);
printf("arr[2] = %d\n", arr[2]);
return 0;
}
bug.c 内容(数组越界 + 空指针写入,用于演示段错误定位):
#include <stdio.h>
int main() {
int arr[4] = {1, 2, 3, 4};
int i;
for (i = 0; i < 100; i++) {
arr[i] = i * 10;
}
int *p = (int *)0x0;
*p = 123;
printf("done\n");
return 0;
}
编译(-g 生成调试符号,-O0 关闭优化便于单步查看):
gcc -g -O0 -o debugme debugme.c
gcc -g -o bug bug.c
编译成功无输出,确认产物:
ls -lh /opt/devchain-demo/gdb-ubuntu-test/
实测回显:
total 48K
-rwxr-xr-x 1 root root 17K Oct 6 06:34 bug
-rw-r--r-- 1 root root 215 Oct 6 06:34 bug.c
-rwxr-xr-x 1 root root 18K Oct 6 06:34 debugme
-rw-r--r-- 1 root root 365 Oct 6 06:34 debugme.c
5.1 命令行参数
5.1.1 --version:查看版本号
gdb --version
实测回显:
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
💡 说明:第一行即版本信息:"GNU gdb (Ubuntu 12.1-0ubuntu1
22.04.2) 12.1",其中 12.1 为 GDB 版本号,12.1-0ubuntu122.04.2 为 Ubuntu 打包版本。
5.1.2 -q(--quiet / --silent):安静模式
不加 -q 启动时,GDB 会先打印版权与配置信息 banner:
gdb /opt/devchain-demo/gdb-ubuntu-test/debugme
实测回显:
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04.2) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /opt/devchain-demo/gdb-ubuntu-test/debugme...
(gdb)
加 -q 后不再打印上述 banner:
gdb -q /opt/devchain-demo/gdb-ubuntu-test/debugme
实测回显:
Reading symbols from /opt/devchain-demo/gdb-ubuntu-test/debugme...
(gdb)
💡 说明:脚本化或批处理调用 GDB 时建议始终加
-q,输出更干净。
5.1.3 --batch:批处理模式
--batch 使 GDB 处理完所有命令后自动退出,不进入交互提示符,适合脚本调用:
gdb -q -batch -ex "info files" /opt/devchain-demo/gdb-ubuntu-test/debugme
实测回显:
Symbols from "/opt/devchain-demo/gdb-ubuntu-test/debugme".
Local exec file:
`/opt/devchain-demo/gdb-ubuntu-test/debugme', file type elf64-x86-64.
Entry point: 0x1080
0x0000000000000318 - 0x0000000000000334 is .interp
0x0000000000000338 - 0x0000000000000368 is .note.gnu.property
0x0000000000000368 - 0x000000000000038c is .note.gnu.build-id
0x000000000000038c - 0x00000000000003ac is .note.ABI-tag
0x00000000000003b0 - 0x00000000000003d4 is .gnu.hash
0x00000000000003d8 - 0x0000000000000498 is .dynsym
0x0000000000000498 - 0x0000000000000542 is .dynstr
0x0000000000000542 - 0x0000000000000552 is .gnu.version
0x0000000000000558 - 0x0000000000000598 is .gnu.version_r
0x0000000000000598 - 0x0000000000000658 is .rela.dyn
0x0000000000000658 - 0x0000000000000688 is .rela.plt
0x0000000000001000 - 0x000000000000101b is .init
0x0000000000001020 - 0x0000000000001050 is .plt
0x0000000000001050 - 0x0000000000001060 is .plt.got
0x0000000000001060 - 0x0000000000001080 is .plt.sec
0x0000000000001080 - 0x0000000000001260 is .text
0x0000000000001260 - 0x000000000000126d is .fini
0x0000000000002000 - 0x0000000000002019 is .rodata
0x000000000000201c - 0x0000000000002058 is .eh_frame_hdr
0x0000000000002058 - 0x0000000000002124 is .eh_frame
0x0000000000003db0 - 0x0000000000003db8 is .init_array
0x0000000000003db8 - 0x0000000000003dc0 is .fini_array
0x0000000000003dc0 - 0x0000000000003fb0 is .dynamic
0x0000000000003fb0 - 0x0000000000004000 is .got
0x0000000000004000 - 0x0000000000004010 is .data
0x0000000000004010 - 0x0000000000004018 is .bss
💡 说明:
info files输出可执行文件各内存段的地址范围,可看出 ELF 布局(.text 代码段、.data 数据段、.bss 未初始化数据段等)。
5.1.4 -ex(--eval-command):执行单条 GDB 命令
-ex 可在启动时直接执行一条 GDB 命令,可多次使用,多个 -ex 按顺序执行:
gdb -batch -ex "break main" -ex "run" -ex "info locals" -ex "quit" /opt/devchain-demo/gdb-ubuntu-test/debugme
实测回显:
Breakpoint 1 at 0x1193: file debugme.c, line 8.
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
x = 0
y = 0
arr = {-753024567, 32766, 100, 0, 4096}
i = 529267711
A debugging session is active.
Inferior 1 [process 8079] will be killed.
Quit anyway? (y or n) [answered Y; input not from terminal]
💡 说明:程序刚在 main 入口停下,
info locals显示各局部变量尚未初始化(x、y 为 0,arr 与 i 为栈上随机值),这正是"断点停在第一行、赋值未执行"的典型现象。配合-batch,-ex可实现无交互的自动化调试。
⚠️ 注意:回显中的
warning: Error disabling address space randomization: Operation not permitted是受限环境下 GDB 无法关闭内核地址空间随机化(ASLR)时给出的提示,不影响断点调试功能。若在意可执行sudo sysctl -w kernel.randomize_va_space=0后重试。
5.1.5 --args:向被调试程序传参
--args 使后面所有参数都作为被调试程序的命令行参数传入:
gdb -batch -ex run --args /opt/devchain-demo/gdb-ubuntu-test/debugme 1 2 3
实测回显:
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
y = 30
arr[2] = 6
[Inferior 1 (process 9502) exited normally]
💡 说明:程序携带 1 2 3 三个参数运行并正常退出。交互会话中可用
set args 1 2 3达到同样效果(见 5.2.17)。
5.1.6 -p(--pid):附加到运行中的进程
先用 sleep 启动一个长驻进程模拟线上程序,记录其 PID:
sleep 300 &
实测回显:
8159
用 gdb -q -p <pid> 附加调试:
gdb -q -p 8159
实测回显:
Attaching to process 8159
Reading symbols from /usr/bin/sleep...
(No debugging symbols found in /usr/bin/sleep)
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/.build-id/6a/6cb5a80fd5e5bb5bf3aeaa111add98e88843a5.debug...
Reading symbols from /lib64/ld-linux-x86-64.so.2...
Reading symbols from /usr/lib/debug/.build-id/e6/d3f5d4f2a24a5464ab59ae321b9474d70410f8.debug...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007e139843b74a in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=0x7ffd14796130, rem=0x7ffd14796130) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
78 ../sysdeps/unix/sysv/linux/clock_nanosleep.c: No such file or directory.
(gdb)
💡 说明:GDB 成功附加到 PID 8159,并自动停在进程当前正在执行的内核调用处(sleep 的内部实现 clock_nanosleep)。由于 /usr/bin/sleep 未带调试符号,显示为汇编级位置。附加模式常用于排查线上异常进程。退出时 GDB 默认"分离"而非杀死目标进程。
⚠️ 注意:
gdb -p附加需要与目标进程相同的权限(一般要求 root 或同一用户),且系统需允许 ptrace。附加的是真实进程,调试完应使用detach正常分离,避免误杀线上服务。
5.1.7 -c(--core):分析 core 转储文件
--core=COREFILE 或直接以 gdb <可执行文件> <core 文件> 形式用于分析程序崩溃产生的 core 转储文件,可还原崩溃现场。
⚠️ 注意:Ubuntu 22.04 默认通过 systemd-coredump 托管 core 文件。实测确认当前系统 core_pattern 为管道转发给 systemd-coredump:
cat /proc/sys/kernel/core_pattern
实测回显:
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e
即崩溃时不会在程序目录生成 core 文件(实测运行崩溃程序后目录内无 core 文件)。如需获得 core 文件,可用 coredumpctl 查询托管记录,或在配置说明中修改 core_pattern(见第六章)。因此本环境暂不演示 -c 的直接用法,命令格式为:
gdb -q /path/to/program /path/to/core
5.1.8 -x(--command=FILE):从文件读取命令
-x file 可从文本文件批量执行 GDB 命令,每行一条,与多条 -ex 等效。适合把常用调试流程固化为脚本文件复用:
gdb -q -batch -x /tmp/gdb.cmd /opt/devchain-demo/gdb-ubuntu-test/debugme
💡 说明:该参数在
gdb --help的 "Initial commands and command files" 一节有说明,与-ex可混用。
5.2 交互命令(gdb 会话内)
以下命令均在 gdb -q 交互会话内执行。启动会话:
gdb -q /opt/devchain-demo/gdb-ubuntu-test/debugme
5.2.1 break(b):设置断点
支持按函数名、文件名:行号、行号等方式设置断点:
(gdb) break main
(gdb) break add
(gdb) break debugme.c:10
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) break add
Breakpoint 2 at 0x1177: file debugme.c, line 4.
(gdb) break debugme.c:10
Breakpoint 3 at 0x11a9: file debugme.c, line 10.
💡 说明:
break main在 main 函数入口(debugme.c 第 8 行)设断点;break add在 add 函数入口(第 4 行);break debugme.c:10按"文件:行号"精确指定到第 10 行。
5.2.2 info breakpoints:查看断点列表
(gdb) info breakpoints
实测回显:
(gdb) Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000001193 in main at debugme.c:8
2 breakpoint keep y 0x0000000000001177 in add at debugme.c:4
3 breakpoint keep y 0x00000000000011a9 in main at debugme.c:10
删除 3 号断点后再查看:
(gdb) delete 3
(gdb) info breakpoints
实测回显:
(gdb) Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000001193 in main at debugme.c:8
2 breakpoint keep y 0x0000000000001177 in add at debugme.c:4
💡 说明:Num 为断点编号(delete 命令按编号删除);Disp 为触发后的处置(keep 表示保留);Enb 为启用状态;What 为断点位置描述。
5.2.3 run(r):运行程序
(gdb) break main
(gdb) run
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb)
💡 说明:
run从程序起点开始执行,命中 main 断点后停下,并提示当前文件与行号。程序未运行到终点时再次run会先询问是否终止当前运行。
5.2.4 start:启动并在 main 停下
start 相当于"自动在 main 设临时断点并 run",比 break main + run 更快捷:
(gdb) start
实测回显:
(gdb) Temporary breakpoint 1 at 0x1193: file debugme.c, line 8.
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb)
💡 说明:该临时断点在命中后自动删除(Temporary breakpoint)。
5.2.5 next(n):单步执行(不进入函数)
(gdb) break main
(gdb) run
(gdb) next
(gdb) next
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) next
9 int x = 10;
(gdb) next
10 int y = 20;
(gdb)
💡 说明:
next按源码行单步推进,遇到函数调用会整行跳过(不进入被调函数内部)。执行两次后停在第 10 行,此时第 9 行int x = 10;已执行。
5.2.6 step(s):单步执行(进入函数)
在函数调用行(第 17 行 y = add(x, y);)使用 step 会进入 add 函数内部:
(gdb) break debugme.c:17
(gdb) run
(gdb) step
实测回显:
(gdb) break debugme.c:17
Breakpoint 1 at 0x1201: file debugme.c, line 17.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:17
17 y = add(x, y);
(gdb) step
add (a=10, b=20) at debugme.c:4
4 int sum = a + b;
(gdb)
💡 说明:
step进入 add 函数并停在函数第一行(第 4 行),同时显示实参 a=10、b=20。next 与 step 的差别就在"是否进入被调函数"。
5.2.7 continue(c):继续运行至下一个断点或程序结束
(gdb) break main
(gdb) run
(gdb) next
(gdb) next
(gdb) print x
(gdb) print y
(gdb) info locals
(gdb) continue
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) next
9 int x = 10;
(gdb) next
10 int y = 20;
(gdb) print x
$1 = 10
(gdb) print y
$2 = 0
(gdb) info locals
x = 10
y = 0
arr = {1069498329, 32766, 100, 0, 4096}
i = 529267711
(gdb) continue
Continuing.
y = 30
arr[2] = 6
[Inferior 1 (process 8423) exited normally]
(gdb)
💡 说明:
continue让程序继续执行,最终程序打印y = 30、arr[2] = 6并正常退出。注意 print y 时第 10 行尚未执行,故 y 仍为 0;$1、$2是 GDB 为每次 print 结果自动编号的历史值,后续可用$1引用。
5.2.8 print(p):打印表达式 / 变量 / 函数调用
(gdb) break add
(gdb) run
(gdb) print add(3,4)
实测回显:
(gdb) break add
Breakpoint 1 at 0x1177: file debugme.c, line 4.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, add (a=10, b=20) at debugme.c:4
4 int sum = a + b;
(gdb) print add(3,4)
Breakpoint 1, add (a=3, b=4) at debugme.c:4
4 int sum = a + b;
The program being debugged stopped while in a function called from GDB.
Evaluation of the expression containing the function
(add) will be abandoned.
When the function is done executing, GDB will silently stop.
(gdb)
💡 说明:
print add(3,4)会在调试器中直接调用 add 函数求值。由于断点仍在 add 上,调用 add(3,4) 再次触发断点,GDB 提示"正在 GDB 内部调用函数时再次停下",随后函数执行完毕返回 7。若先delete 1删除断点再 print,则直接显示$1 = 7。
打印地址与数组:
(gdb) print x
(gdb) print &x
(gdb) print arr
(gdb) ptype arr
在 main 内停到第 14 行(arr 已初始化)后实测回显:
(gdb) print arr
$1 = {1, 2, 3, 4, 5}
(gdb) ptype arr
type = int [5]
5.2.9 ptype:查看变量类型
(gdb) ptype arr
实测回显:
(gdb) type = int [5]
💡 说明:
ptype输出表达式的类型定义。对结构体、数组、指针均适用,是快速了解数据结构的利器。
5.2.10 backtrace(bt):查看调用栈
在 add 函数内查看完整调用链:
(gdb) break add
(gdb) run
(gdb) backtrace
实测回显:
(gdb) break add
Breakpoint 1 at 0x1177: file debugme.c, line 4.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, add (a=10, b=20) at debugme.c:4
4 int sum = a + b;
(gdb) backtrace
#0 add (a=10, b=20) at debugme.c:4
#1 0x0000571a7c397210 in main () at debugme.c:17
(gdb)
💡 说明:#0 为当前帧(add),#1 为调用者(main 第 17 行调用 add 的位置)。
bt full可同时显示各帧的局部变量。
5.2.11 info locals / info args:查看局部变量与函数参数
(gdb) break add
(gdb) run
(gdb) info args
(gdb) info locals
实测回显:
(gdb) break add
Breakpoint 1 at 0x1177: file debugme.c, line 4.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, add (a=10, b=20) at debugme.c:4
4 int sum = a + b;
(gdb) info args
a = 10
b = 20
(gdb) info locals
sum = 32766
(gdb)
💡 说明:
info args显示当前帧函数入参(a=10、b=20);info locals显示局部变量,sum 尚未赋值,为栈上随机值。
5.2.12 info registers:查看 CPU 寄存器
(gdb) break main
(gdb) run
(gdb) info registers rsp rbp rip
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) info registers rsp rbp rip
rsp 0x7ffff0121160 0x7ffff0121160
rbp 0x7ffff0121190 0x7ffff0121190
rip 0x577c6b330193 0x577c6b330193 <main+12>
(gdb)
💡 说明:
info registers不带参数时输出全部通用寄存器;带寄存器名则只显示指定项。rsp/rbp 为栈指针/帧指针,rip 为指令指针(显示当前停驻指令 <main+12>)。这是汇编级分析的基础。
5.2.13 info functions:查看函数列表
(gdb) info functions add
实测回显(节选,输出较长只取与本程序相关的部分):
(gdb) All functions matching regular expression "add":
File debugme.c:
3: int add(int, int);
File ../elf/dl-tls.c:
944: void *___tls_get_addr(tls_index *);
1014: void _dl_add_to_slotinfo(struct link_map *, _Bool);
...
💡 说明:
info functions <正则>按正则匹配列出函数;info functions不带参数列出全部函数。节选中可见本程序的add(int, int)(debugme.c 第 3 行)以及 glibc 中名称含 add 的函数。
5.2.14 watch:设置观察点(数据变化即停)
监视变量 y,一旦其值变化程序即暂停:
(gdb) break main
(gdb) run
(gdb) watch y
(gdb) continue
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) watch y
Hardware watchpoint 2: y
(gdb) continue
Continuing.
Hardware watchpoint 2: y
Old value = 0
New value = 20
main () at debugme.c:11
11 int arr[5] = {1, 2, 3, 4, 5};
(gdb)
💡 说明:
watch y创建硬件观察点(编号 2)。continue 后程序执行到第 10 行int y = 20;,y 从 0 变为 20,观察点触发并停在第 11 行,精确指出"y 在何时、何地被修改"。
5.2.15 set var:运行时修改变量
(gdb) break main
(gdb) run
(gdb) print x
(gdb) set var x = 100
(gdb) print x
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) print x
$1 = 10
(gdb) set var x = 100
(gdb) print x
$2 = 100
(gdb)
💡 说明:
set var x = 100把变量 x 从 10 改为 100(print x后 x 为 10,修改后为 100),后续程序逻辑将基于新值执行。常用于绕过错误分支、临时构造测试数据。
5.2.16 disassemble:反汇编
(gdb) break main
(gdb) run
(gdb) disassemble main
实测回显(节选,=> 标记当前执行指令):
(gdb) Dump of assembler code for function main:
0x00005c0270b6a187 <+0>: endbr64
0x00005c0270b6a18b <+4>: push %rbp
0x00005c0270b6a18c <+5>: mov %rsp,%rbp
0x00005c0270b6a18f <+8>: sub $0x30,%rsp
0x00005c0270b6a193 <+12>: mov %fs:0x28,%rax
0x00005c0270b6a19c <+21>: mov %rax,-0x8(%rbp)
0x00005c0270b6a1a0 <+25>: xor %eax,%eax
0x00005c0270b6a1a2 <+27>: movl $0xa,-0x24(%rbp)
0x00005c0270b6a1a9 <+34>: movl $0x14,-0x2c(%rbp)
0x00005c0270b6a1b0 <+41>: movl $0x1,-0x20(%rbp)
0x00005c0270b6a1b7 <+48>: movl $0x2,-0x1c(%rbp)
0x00005c0270b6a1be <+55>: movl $0x3,-0x18(%rbp)
0x00005c0270b6a1c5 <+62>: movl $0x4,-0x14(%rbp)
0x00005c0270b6a1cc <+69>: movl $0x5,-0x10(%rbp)
0x00005c0270b6a1d3 <+76>: movl $0x0,-0x28(%rbp)
0x00005c0270b6a1da <+83>: jmp 0x5c0270b6a1f5 <main+110>
=> 0x00005c0270b6a1dc <+85>: mov -0x28(%rbp),%eax
0x00005c0270b6a1df <+88>: cltq
0x00005c0270b6a1e1 <+90>: mov -0x20(%rbp,%rax,4),%eax
0x00005c0270b6a1e5 <+94>: lea (%rax,%rax,1),%edx
0x00005c0270b6a1e8 <+97>: mov -0x28(%rbp),%eax
0x00005c0270b6a1eb <+100>: cltq
0x00005c0270b6a1ed <+102>: mov %edx,-0x20(%rbp,%rax,4)
0x00005c0270b6a1f1 <+106>: addl $0x1,-0x28(%rbp)
0x00005c0270b6a1f5 <+110>: cmpl $0x4,-0x28(%rbp)
0x00005c0270b6a1f9 <+114>: jle 0x5c0270b6a1dc <main+85>
0x00005c0270b6a1fb <+116>: cmpl $0x5,-0x24(%rbp)
0x00005c0270b6a1ff <+120>: jle 0x5c0270b6a213 <main+140>
0x00005c0270b6a201 <+122>: mov -0x2c(%rbp),%edx
0x00005c0270b6a204 <+125>: mov -0x24(%rbp),%eax
0x00005c0270b6a207 <+128>: mov %edx,%esi
0x00005c0270b6a209 <+130>: mov %eax,%edi
0x00005c0270b6a20b <+132>: call 0x5c0270b6a169 <add>
0x00005c0270b6a210 <+137>: mov %eax,-0x2c(%rbp)
0x00005c0270b6a213 <+140>: mov -0x2c(%rbp),%eax
0x00005c0270b6a216 <+143>: mov %eax,%esi
0x00005c0270b6a218 <+145>: lea 0xde5(%rip),%rax # 0x5c0270b6b004
0x00005c0270b6a21f <+152>: mov %rax,%rdi
0x00005c0270b6a222 <+155>: mov $0x0,%eax
0x00005c0270b6a227 <+160>: call 0x5c0270b6a070 <printf@plt>
0x00005c0270b6a22c <+165>: mov -0x18(%rbp),%eax
0x00005c0270b6a22f <+168>: mov %eax,%esi
0x00005c0270b6a231 <+170>: lea 0xdd4(%rip),%rax # 0x5c0270b6b00c
0x00005c0270b6a238 <+177>: mov %rax,%rdi
0x00005c0270b6a23b <+180>: mov $0x0,%eax
0x00005c0270b6a240 <+185>: call 0x5c0270b6a070 <printf@plt>
0x00005c0270b6a245 <+190>: mov $0x0,%eax
0x00005c0270b6a24a <+195>: mov -0x8(%rbp),%rdx
0x00005c0270b6a24e <+199>: sub %fs:0x28,%rdx
0x00005c0270b6a257 <+208>: je 0x5c0270b6a25e <main+215>
0x00005c0270b6a259 <+210>: call 0x5c0270b6a060 <__stack_chk_fail@plt>
0x00005c0270b6a25e <+215>: leave
0x00005c0270b6a25f <+216>: ret
End of assembler dump.
💡 说明:可从汇编看到
-O0优化下每个源码行对应的指令序列,例如数组翻倍循环对应 <+85>~<+114> 段;call <add>即调用 add 函数。当前停驻指令(数组循环体内)以=>标注。
5.2.17 list(l):查看源码
三种形式:list(当前上下文)、list main(函数)、list 1,10(指定行范围):
(gdb) list
(gdb) list main
(gdb) list 1,10
实测回显(停在第 14 行附近执行):
(gdb) list
9 int x = 10;
10 int y = 20;
11 int arr[5] = {1, 2, 3, 4, 5};
12 int i;
13 for (i = 0; i < 5; i++) {
14 arr[i] = arr[i] * 2;
15 }
16 if (x > 5) {
17 y = add(x, y);
18 }
(gdb) list main
3 int add(int a, int b) {
4 int sum = a + b;
5 return sum;
6 }
7
8 int main() {
9 int x = 10;
10 int y = 20;
11 int arr[5] = {1, 2, 3, 4, 5};
12 int i;
(gdb) list 1,10
1 #include <stdio.h>
2
3 int add(int a, int b) {
4 int sum = a + b;
5 return sum;
6 }
7
8 int main() {
9 int x = 10;
10 int y = 20;
(gdb)
💡 说明:
list每次显示 10 行;list main从函数开头显示;list 1,10精确显示第 1 至第 10 行。
5.2.18 x:查看内存
x/<数量><格式><单位> <地址>,例如 x/20xw &arr 以十六进制(x)按 4 字节字(w)查看数组起始地址处 20 个字:
(gdb) x/20xw &arr
实测回显:
(gdb) 0x7fffbe036f40: 0x00000001 0x00000002 0x00000003 0x00000004
0x7fffbe036f50: 0x00000005 0x00000000 0x7685ff00 0x702c3db8
0x7fffbe036f60: 0x00000001 0x00000000 0x639f7d90 0x000072fb
0x7fffbe036f70: 0x00000000 0x00000000 0x70b6a187 0x00005c02
0x7fffbe036f80: 0xbe037060 0x00000001 0xbe037078 0x00007fff
💡 说明:前 5 个字(0x1~0x5)即 arr[0]~arr[4] 的值,其后为栈上相邻数据。
x/i $pc则以指令格式反汇编当前指令:
(gdb) x/i $pc
实测回显:
(gdb) => 0x558177653193 <main+12>: mov %fs:0x28,%rax
💡 说明:
$pc是程序计数器(指令指针)寄存器,x/i $pc显示即将执行的汇编指令,与 disassemble 配合可用于汇编级单步。
5.2.19 help:查看命令帮助
(gdb) help break
实测回显(节选):
(gdb) break, brea, bre, br, b
Set breakpoint at specified location.
break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]
[-force-condition] [if CONDITION]
...
Linespecs are colon-separated lists of location parameters, such as
source filename, function name, label name, and line number.
Example: To specify the start of a label named "the_top" in the
function "fact" in the file "factorial.c", use
"factorial.c:fact:the_top".
Address locations begin with "*" and specify an exact address in the
program. Example: To specify the fourth byte past the start function
"main", use "*main + 4".
...
(gdb) help run
实测回显(节选):
(gdb) run, r
Start debugged program.
You may specify arguments to give it.
Args may include "*", or "[...]"; they are expanded using the
shell that will start the program (specified by the "$SHELL" environment
variable). Input and output redirection with ">", "<", or ">>"
are also allowed.
With no arguments, uses arguments last specified (with "run" or
"set args"). To cancel previous arguments and run with no arguments,
use "set args" without arguments.
💡 说明:
help <命令>可查看任意命令的用法,包括参数格式与示例;help不带参数列出全部命令分类。
5.2.20 kill:终止被调试程序
(gdb) break main
(gdb) run
(gdb) kill
实测回显:
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) kill
Kill the program being debugged? (y or n) [answered Y; input not from terminal]
[Inferior 1 (process 9121) killed]
(gdb)
💡 说明:
kill终止当前被调试的进程(有确认提示),之后可重新run或退出。附加模式(-p)下请使用detach分离而不是kill。
5.2.21 set args / show args:设置与查看运行参数
(gdb) set args 1 2 3
(gdb) show args
(gdb) break main
(gdb) run
(gdb) info args
实测回显:
(gdb) set args 1 2 3
(gdb) show args
Argument list to give program being debugged when it is started is "1 2 3".
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme 1 2 3
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) info args
No arguments.
(gdb)
💡 说明:
set args 1 2 3后run会以参数 "1 2 3" 启动程序(见 Starting program 行)。本演示程序 main 未声明参数,故info args显示 No arguments;若程序使用 argc/argv 即可读到参数。print argc在本程序会提示No symbol "argc" in current context。
5.2.22 finish:运行到当前函数返回
(gdb) break add
(gdb) run
(gdb) finish
实测回显:
(gdb) break add
Breakpoint 1 at 0x1177: file debugme.c, line 4.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, add (a=10, b=20) at debugme.c:4
4 int sum = a + b;
(gdb) finish
Run till exit from #0 add (a=10, b=20) at debugme.c:4
add (a=10, b=20) at debugme.c:4
4 int sum = a + b;
Value returned is $1 = 30
(gdb)
💡 说明:
finish一直执行到当前函数返回并打印返回值:Value returned is $1 = 30(add(10,20) 的结果 30)。常用于跳过已确认正确的函数、直接观察其返回值。
5.2.23 quit(q):退出 GDB
程序仍在运行(未运行完)时退出,GDB 会询问是否终止会话:
(gdb) quit
实测回显:
(gdb) A debugging session is active.
Inferior 1 [process 8467] will be killed.
Quit anyway? (y or n) [answered Y; input not from terminal]
(gdb)
💡 说明:输入
y确认后退出,GDB 会终止被调试进程。程序已正常结束时直接quit即可退出。
5.3 完整调试会话(组合演练)
下面把以上命令组合成一次完整的调试会话:设断点 → 单步 → 查看变量 → 打印函数调用 → 修改数据 → 观察点 → 查看调用栈与反汇编 → 继续运行至结束。
$ gdb -q /opt/devchain-demo/gdb-ubuntu-test/debugme
Reading symbols from /opt/devchain-demo/gdb-ubuntu-test/debugme...
(gdb) break main
Breakpoint 1 at 0x1193: file debugme.c, line 8.
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/debugme
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at debugme.c:8
8 int main() {
(gdb) next
9 int x = 10;
(gdb) next
10 int y = 20;
(gdb) next
11 int arr[5] = {1, 2, 3, 4, 5};
(gdb) next
13 for (i = 0; i < 5; i++) {
(gdb) next
14 arr[i] = arr[i] * 2;
(gdb) print arr
$1 = {1, 2, 3, 4, 5}
(gdb) ptype arr
type = int [5]
(gdb) x/20xw &arr
0x7fffbe036f40: 0x00000001 0x00000002 0x00000003 0x00000004
0x7fffbe036f50: 0x00000005 0x00000000 0x7685ff00 0x702c3db8
0x7fffbe036f60: 0x00000001 0x00000000 0x639f7d90 0x000072fb
0x7fffbe036f70: 0x00000000 0x00000000 0x70b6a187 0x00005c02
0x7fffbe036f80: 0xbe037060 0x00000001 0xbe037078 0x00007fff
(gdb) list
9 int x = 10;
10 int y = 20;
11 int arr[5] = {1, 2, 3, 4, 5};
12 int i;
13 for (i = 0; i < 5; i++) {
14 arr[i] = arr[i] * 2;
15 }
16 if (x > 5) {
17 y = add(x, y);
18 }
(gdb) disassemble main
Dump of assembler code for function main:
0x00005c0270b6a187 <+0>: endbr64
...
=> 0x00005c0270b6a1dc <+85>: mov -0x28(%rbp),%eax
...
0x00005c0270b6a20b <+132>: call 0x5c0270b6a169 <add>
...
End of assembler dump.
(gdb) x/i $pc
=> 0x00005c0270b6a1dc <main+85>: mov -0x28(%rbp),%eax
(gdb) continue
Continuing.
y = 30
arr[2] = 6
[Inferior 1 (process 8594) exited normally]
(gdb) quit
💡 说明:一次完整会话展示了"源码级 → 内存级 → 汇编级"三层观察手段的组合使用。调试结束程序已正常退出,
quit直接退出无确认提示。
5.4 段错误定位实战(核心演示)
用带缺陷的 bug 程序演示崩溃定位:数组越界写入 + 空指针解引用。
启动调试:
gdb -q /opt/devchain-demo/gdb-ubuntu-test/bug
输入 run 直接运行,程序崩溃:
(gdb) run
Starting program: /opt/devchain-demo/gdb-ubuntu-test/bug
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0000561b8befa1d6 in main () at bug.c:10
10 *p = 123;
(gdb)
💡 说明:GDB 捕获 SIGSEGV 段错误信号并直接定位到出错的源码行:bug.c 第 10 行
*p = 123;。
继续回溯调用栈与现场:
(gdb) backtrace
#0 0x0000561b8befa1d6 in main () at bug.c:10
(gdb) list
5 int i;
6 for (i = 0; i < 100; i++) {
7 arr[i] = i * 10;
8 }
9 int *p = (int *)0x0;
10 *p = 123;
11 printf("done\n");
12 return 0;
13 }
(gdb) info locals
arr = {0, 10, 20, 30}
i = 100
p = 0x0
(gdb) info registers rip
rip 0x561b8befa1d6 0x561b8befa1d6 <main+109>
(gdb) quit
💡 说明:结合
backtrace(崩溃点调用栈)、list(出错行上下文)、info locals(现场变量:p=0x0 即空指针)即可完整还原崩溃原因:向地址 0x0 写入数据导致段错误;同时arr[i] = i * 10在 i 到 100 时已越界写出数组边界,是另一处潜在缺陷。定位到行后回到源码修正即可。
5.5 core 转储文件说明
- Ubuntu 22.04 默认 core_pattern 为
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e,崩溃时 core 由 systemd-coredump 托管,不会在当前目录生成 core 文件(实测ulimit -c unlimited后运行崩溃程序,目录内无 core 文件生成)。 - 需要 core 文件时:可执行
coredumpctl查看托管记录,或用coredumpctl dump <程序名>导出;也可修改 core_pattern 使 core 落盘到指定路径(见第六章)。 - 拿到 core 文件后即可用
gdb -c core 文件 可执行文件离线分析崩溃现场,无需复现崩溃。
六、配置说明
6.1 启动初始化文件 .gdbinit
GDB 启动时会依次读取系统级初始化文件 /etc/gdb/gdbinit 与用户级 ~/.gdbinit,文件内每行一条 GDB 命令,例如:
cat ~/.gdbinit
示例内容:
set pagination off
set print pretty on
💡 说明:
set pagination off关闭分页(长输出不再逐屏暂停,适合脚本);set print pretty on使结构体/数组按缩进美观打印。修改后下次启动 GDB 自动生效;命令行加-nx可跳过所有 .gdbinit 文件。
6.2 常用 set 配置
| 命令 | 作用 |
|---|---|
| set pagination off | 关闭输出分页 |
| set print pretty on | 美化结构体打印 |
| set confirm off | 关闭危险操作确认提示(如 quit/kill) |
| set args "参数列表" | 预置程序运行参数(见 5.2.21) |
| set var 变量 = 值 | 运行时修改变量(见 5.2.15) |
6.3 core 落盘配置(可选)
如需崩溃时在本地目录生成 core 文件,可修改 core_pattern:
echo 'core' > /proc/sys/kernel/core_pattern
ulimit -c unlimited
⚠️ 注意:
/proc/sys/kernel/core_pattern的修改重启后失效;如需持久化可写入 /etc/sysctl.d/ 下的配置文件。ulimit -c unlimited只对当前 shell 会话有效。
七、常见问题(FAQ)
7.1 运行 run 出现 "Error disabling address space randomization: Operation not permitted"
受限环境下 GDB 无法修改内核 ASLR 开关导致的提示,不影响断点、单步等调试功能。若需要关闭 ASLR,可执行:
sudo sysctl -w kernel.randomize_va_space=0
7.2 提示 "No debugging symbols found" / 单步看不到源码行
可执行文件未包含调试符号。使用 gcc 编译时务必加 -g 选项,且调试期建议 -O0 关闭优化(优化后的代码行与源码行不再一一对应)。验证方式:
file /opt/devchain-demo/gdb-ubuntu-test/debugme
实测回显:
/opt/devchain-demo/gdb-ubuntu-test/debugme: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., for GNU/Linux 3.2.0, with debug_info, not stripped
7.3 断点不停或行号错位
多因编译优化(-O2/-O3)导致指令与源码行映射错位,或代码改动后未重新编译。清理并加 -g -O0 重新编译即可。
7.4 附加进程时提示 "Operation not permitted"
ptrace 权限受限(Yama 安全模块)。临时放开:
sudo sysctl -w kernel.yama.ptrace_scope=0
7.5 段错误但不知道在哪
直接运行崩溃程序,再用 GDB 的 run + backtrace(见 5.4 实战)即可定位崩溃行与调用栈;若 core 由 systemd-coredump 托管,也可用 coredumpctl 查询历史崩溃记录。
7.6 退出时总是询问 "Quit anyway?"
程序尚未运行完时退出 GDB 的确认提示。可先 continue 让程序结束,或执行 kill 后再 quit,或设置 set confirm off 关闭确认。
八、卸载与清理
8.1 查看当前安装状态
dpkg -l gdb
实测回显:
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==============-=====================-============-=================================
ii gdb 12.1-0ubuntu1~22.04.2 amd64 GNU Debugger
💡 说明:状态列
ii表示已安装且配置完好。
8.2 查看软件包详细信息
apt-cache show gdb
实测回显(头部):
Package: gdb
Priority: optional
Section: devel
Installed-Size: 11313
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Version: 12.1-0ubuntu1~22.04.2
Recommends: libc-dbg
Replaces: gdb
Suggests: gdb-doc, gdbserver
Provides: gdb-minimal (= 12.1-0ubuntu1~22.04.2)
Depends: libbabeltrace1 (>= 1.5.4), libc6 (>= 2.34), libdebuginfod1 (>= 0.180), libexpat1 (>= 2.0.1), libgcc-s1 (>= 4.2), libgmp10 (>= 2:6.2.1+dfsg), libipt2 (>= 2.0), liblzma5 (>= 5.1.1alpha+20110809), libmpfr6 (>= 3.1.3), libncursesw6 (>= 6), libpython3.10 (>= 3.10.0), libreadline8 (>= 8), libsource-highlight4v5 (>= 3.1.9), libstdc++6 (>= 12), libtinfo6 (>= 6), libxxhash0 (>= 0.6.5), zlib1g (>= 1:1.2.0)
8.3 卸载 GDB
仅移除程序,保留配置文件:
sudo apt remove gdb
连同配置文件一并移除:
sudo apt remove --purge gdb
💡 说明:
remove卸载软件本体;--purge额外删除配置文件。卸载后可用dpkg -l gdb复核(状态列变为 rc 或不再显示)。
8.4 清理下载缓存(可选)
sudo apt clean
💡 说明:
apt clean清空 /var/cache/apt/archives/ 下已下载的 .deb 包,释放磁盘空间;本次离线安装目录 /opt/devchain-demo/gdb-ubuntu-test/offline/ 如需清理可手动删除。
九、参考链接
- GDB 官方文档:https://www.gnu.org/software/gdb/documentation/
- GDB 调试器手册(GNU Debugger Manual):https://sourceware.org/gdb/current/onlinedocs/gdb/
- Ubuntu 软件包 gdb 页面:https://packages.ubuntu.com/jammy/gdb
- GNU 项目主页:https://www.gnu.org/software/gdb/