Ubuntu 22.04 GDB 安装与命令参数详解

Ubuntu 22.04 下 GDB 12.1 在线/离线安装、全部命令行参数与交互调试命令详解,含完整调试会话与段错误定位实战。

Linux开发与编译工具链gdb2026/10/06

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-0ubuntu122.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/ 如需清理可手动删除。

九、参考链接

Ubuntu 22.04 GDB 安装与命令参数详解 - Quzuo