编译与调试完全指南—第5章 GDB调试详解

第5章 GDB调试详解

完整 485 页的 《编译与调试完全指南》见: https://github.com/lengjingzju/notes/releases/tag/v0.0.2

GDB(GNU Debugger)是 Linux 下最强大的源代码级调试器,支持断点设置、单步执行、变量查看、内存检查、多线程/多进程调试、远程调试等核心功能。掌握 GDB 是进行嵌入式开发、系统编程和问题定位的必备技能。本章按照"启动连接→执行控制→断点观察→数据操作→堆栈分析→高级调试→实战场景"的逻辑组织,覆盖 GDB 的完整知识体系。
#mermaid-svg-MZnCtvDqiINSb60U{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MZnCtvDqiINSb60U .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MZnCtvDqiINSb60U .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MZnCtvDqiINSb60U .error-icon{fill:#552222;}#mermaid-svg-MZnCtvDqiINSb60U .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MZnCtvDqiINSb60U .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MZnCtvDqiINSb60U .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MZnCtvDqiINSb60U .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MZnCtvDqiINSb60U .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MZnCtvDqiINSb60U .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MZnCtvDqiINSb60U .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MZnCtvDqiINSb60U .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MZnCtvDqiINSb60U .marker.cross{stroke:#333333;}#mermaid-svg-MZnCtvDqiINSb60U svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MZnCtvDqiINSb60U p{margin:0;}#mermaid-svg-MZnCtvDqiINSb60U .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MZnCtvDqiINSb60U .cluster-label text{fill:#333;}#mermaid-svg-MZnCtvDqiINSb60U .cluster-label span{color:#333;}#mermaid-svg-MZnCtvDqiINSb60U .cluster-label span p{background-color:transparent;}#mermaid-svg-MZnCtvDqiINSb60U .label text,#mermaid-svg-MZnCtvDqiINSb60U span{fill:#333;color:#333;}#mermaid-svg-MZnCtvDqiINSb60U .node rect,#mermaid-svg-MZnCtvDqiINSb60U .node circle,#mermaid-svg-MZnCtvDqiINSb60U .node ellipse,#mermaid-svg-MZnCtvDqiINSb60U .node polygon,#mermaid-svg-MZnCtvDqiINSb60U .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MZnCtvDqiINSb60U .rough-node .label text,#mermaid-svg-MZnCtvDqiINSb60U .node .label text,#mermaid-svg-MZnCtvDqiINSb60U .image-shape .label,#mermaid-svg-MZnCtvDqiINSb60U .icon-shape .label{text-anchor:middle;}#mermaid-svg-MZnCtvDqiINSb60U .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MZnCtvDqiINSb60U .rough-node .label,#mermaid-svg-MZnCtvDqiINSb60U .node .label,#mermaid-svg-MZnCtvDqiINSb60U .image-shape .label,#mermaid-svg-MZnCtvDqiINSb60U .icon-shape .label{text-align:center;}#mermaid-svg-MZnCtvDqiINSb60U .node.clickable{cursor:pointer;}#mermaid-svg-MZnCtvDqiINSb60U .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MZnCtvDqiINSb60U .arrowheadPath{fill:#333333;}#mermaid-svg-MZnCtvDqiINSb60U .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MZnCtvDqiINSb60U .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MZnCtvDqiINSb60U .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MZnCtvDqiINSb60U .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MZnCtvDqiINSb60U .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MZnCtvDqiINSb60U .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MZnCtvDqiINSb60U .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MZnCtvDqiINSb60U .cluster text{fill:#333;}#mermaid-svg-MZnCtvDqiINSb60U .cluster span{color:#333;}#mermaid-svg-MZnCtvDqiINSb60U div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MZnCtvDqiINSb60U .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MZnCtvDqiINSb60U rect.text{fill:none;stroke-width:0;}#mermaid-svg-MZnCtvDqiINSb60U .icon-shape,#mermaid-svg-MZnCtvDqiINSb60U .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MZnCtvDqiINSb60U .icon-shape p,#mermaid-svg-MZnCtvDqiINSb60U .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MZnCtvDqiINSb60U .icon-shape .label rect,#mermaid-svg-MZnCtvDqiINSb60U .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MZnCtvDqiINSb60U .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MZnCtvDqiINSb60U .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MZnCtvDqiINSb60U :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GDB核心功能
启动与连接
程序执行控制
断点与观察点
数据查看与修改
堆栈分析
多线程调试
多进程调试
信号处理
源码与反汇编
自定义命令与脚本

5.1 GDB启动与连接

本节介绍 GDB 的各种启动方式和连接模式,包括本地调试、附加进程、交叉调试和 Coredump 调试。选择合适的启动方式是调试的第一步。

5.1.1 GDB启动参数(控制调试会话初始化)

GDB 提供了丰富的启动参数,用于控制调试会话的初始化行为。使用 gdb --help 可查看所有启动参数的详细说明。

常用选项:

选项 全称 说明
-s <file> --symbols=<file> 从指定文件中读取符号表
-se <file> 从指定文件中读取符号表信息,并把它用在可执行文件中
-c <file> --core=<file> 调试时 core dump 的 core 文件
-d <directory> --directory=<directory> 加入一个源文件的搜索路径(默认搜索路径是环境变量 PATH 所定义的路径)
-nx 不执行 .gdbinit 初始化文件
-nh 不执行家目录的 .gdbinit
-p <pid> --pid=<pid> 绑定到运行中的进程
-x <file> 执行指定的命令文件
-q --quiet 不显示欢迎信息
-batch 批处理模式,执行完命令后自动退出
-ex <command> 启动时执行指定 GDB 命令

实践示例:

bash 复制代码
# 加载符号表和可执行文件
$ gdb -se program

# 加载 core dump 文件进行事后调试
$ gdb -c core.12345

# 添加额外的源文件搜索路径
$ gdb -d /home/user/src -d /opt/project/src program

# 不加载 .gdbinit(排除配置干扰)
$ gdb -nx program

# 直接附加到运行中的进程
$ gdb -p 12345

# 批处理模式:启动后执行命令并退出
$ gdb -batch -ex "bt" -ex "quit" ./program core

# 启动时直接执行命令
$ gdb -ex "set args 3 5" -ex "run" ./myop

.gdbinit 配置文件说明:

如果存在 .gdbinit,GDB 就会在启动之前将其作为命令文件运行。.gdbinit 可能存在于以下位置:

位置 加载顺序 说明
系统级(/etc/gdb/gdbinit 最先 系统全局配置(需编译时启用)
家目录(~/.config/gdb/gdbinit~/.gdbinit 其次 全局个人配置
当前目录(./.gdbinit 再次 项目级配置(需安全授权)
-x 选项指定的文件 最后 命令行指定

5.1.2 本地调试启动(调试本机程序)

调试可执行程序:

bash 复制代码
# 启动 gdb 调试可执行文件
$ gdb <program>

# 进入 gdb 后设置运行参数
(gdb) set args <arg1> <arg2> ...

# 查看运行参数
(gdb) show args

# 开始运行
(gdb) run

# 运行到 main 函数暂停(比 run 更方便)
(gdb) start

实践示例(使用第 1 章的 myop 程序):

bash 复制代码
$ gdb ./myop
(gdb) set args 3 5
(gdb) run
Starting program: /home/user/myop 3 5
3 + 5 = 8
3 - 5 = -2
3 * 5 = 15
3 / 5 = 0
3 ^ 5 = 243.000000
[Inferior 1 (process 12345) exited normally]

调试运行中的进程(3种方式):

方式 命令 示例
方式1:通过 --pid 参数 gdb --pid <pid_num> sudo gdb --pid 1620
方式2:通过程序和进程号绑定 gdb <program> <pid_num> gdb test 3095
方式3:在 GDB 中使用 attach (gdb) attach <pid_num> 先进入 gdb,再 attach
bash 复制代码
# 方式1:直接通过 PID 附加
$ sudo gdb --pid 1620

# 方式2:指定程序和 PID
$ gdb test 3095

# 方式3:先启动 gdb,再 attach
$ gdb
(gdb) attach 3095
Attaching to process 3095
...

# 取消挂接(detach 后进程继续运行)
(gdb) detach

# 继续运行被调试的程序
(gdb) continue

易错点:

易错点 说明
attach 后程序暂停 attach 后程序处于暂停状态,需要 continue 才能继续运行
detach 后进程恢复 detach 后 GDB 不再控制该进程,进程恢复正常运行
权限问题 调试其他用户的进程通常需要 sudo 权限
ptrace 限制 Ubuntu 默认 ptrace_scope=1,只能调试子进程,需修改为 0

5.1.3 交叉调试(远程目标板调试)

交叉调试用于在主机(Host)上调试目标板(Target)上运行的程序,是嵌入式开发的核心调试方式。

前提条件: 目标板文件系统中必须有 gdbserver 工具。gdbserver 负责与远程的 GDB 进行通讯并控制本地的应用程序执行。
#mermaid-svg-yHV5LzDlEK13vfob{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yHV5LzDlEK13vfob .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yHV5LzDlEK13vfob .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yHV5LzDlEK13vfob .error-icon{fill:#552222;}#mermaid-svg-yHV5LzDlEK13vfob .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yHV5LzDlEK13vfob .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yHV5LzDlEK13vfob .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yHV5LzDlEK13vfob .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yHV5LzDlEK13vfob .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yHV5LzDlEK13vfob .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yHV5LzDlEK13vfob .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yHV5LzDlEK13vfob .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yHV5LzDlEK13vfob .marker.cross{stroke:#333333;}#mermaid-svg-yHV5LzDlEK13vfob svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yHV5LzDlEK13vfob p{margin:0;}#mermaid-svg-yHV5LzDlEK13vfob .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yHV5LzDlEK13vfob .cluster-label text{fill:#333;}#mermaid-svg-yHV5LzDlEK13vfob .cluster-label span{color:#333;}#mermaid-svg-yHV5LzDlEK13vfob .cluster-label span p{background-color:transparent;}#mermaid-svg-yHV5LzDlEK13vfob .label text,#mermaid-svg-yHV5LzDlEK13vfob span{fill:#333;color:#333;}#mermaid-svg-yHV5LzDlEK13vfob .node rect,#mermaid-svg-yHV5LzDlEK13vfob .node circle,#mermaid-svg-yHV5LzDlEK13vfob .node ellipse,#mermaid-svg-yHV5LzDlEK13vfob .node polygon,#mermaid-svg-yHV5LzDlEK13vfob .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yHV5LzDlEK13vfob .rough-node .label text,#mermaid-svg-yHV5LzDlEK13vfob .node .label text,#mermaid-svg-yHV5LzDlEK13vfob .image-shape .label,#mermaid-svg-yHV5LzDlEK13vfob .icon-shape .label{text-anchor:middle;}#mermaid-svg-yHV5LzDlEK13vfob .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yHV5LzDlEK13vfob .rough-node .label,#mermaid-svg-yHV5LzDlEK13vfob .node .label,#mermaid-svg-yHV5LzDlEK13vfob .image-shape .label,#mermaid-svg-yHV5LzDlEK13vfob .icon-shape .label{text-align:center;}#mermaid-svg-yHV5LzDlEK13vfob .node.clickable{cursor:pointer;}#mermaid-svg-yHV5LzDlEK13vfob .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yHV5LzDlEK13vfob .arrowheadPath{fill:#333333;}#mermaid-svg-yHV5LzDlEK13vfob .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yHV5LzDlEK13vfob .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yHV5LzDlEK13vfob .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yHV5LzDlEK13vfob .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yHV5LzDlEK13vfob .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yHV5LzDlEK13vfob .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yHV5LzDlEK13vfob .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yHV5LzDlEK13vfob .cluster text{fill:#333;}#mermaid-svg-yHV5LzDlEK13vfob .cluster span{color:#333;}#mermaid-svg-yHV5LzDlEK13vfob div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yHV5LzDlEK13vfob .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yHV5LzDlEK13vfob rect.text{fill:none;stroke-width:0;}#mermaid-svg-yHV5LzDlEK13vfob .icon-shape,#mermaid-svg-yHV5LzDlEK13vfob .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yHV5LzDlEK13vfob .icon-shape p,#mermaid-svg-yHV5LzDlEK13vfob .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yHV5LzDlEK13vfob .icon-shape .label rect,#mermaid-svg-yHV5LzDlEK13vfob .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yHV5LzDlEK13vfob .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yHV5LzDlEK13vfob .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yHV5LzDlEK13vfob :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 目标板 Target
主机 Host
target remote

TCP连接
aarch64-linux-gdb

交叉调试器
gdbserver

调试代理
被调试程序

out.elf

步骤1:在目标板上启动 gdbserver

bash 复制代码
# 语法:gdbserver <host>:<port> <program> &
# <host>:主机名称或IP地址,可以省略
# <port>:网络端口号,可以是目标板上任何可用的端口号
# <program>:需要调试的程序名
# &:后台执行
$ gdbserver 192.168.110.124:2345 out.elf &

# 也可以省略 host(等待任意主机连接)
$ gdbserver :2345 out.elf &

步骤2:在主机端启动交叉调试器

bash 复制代码
$ aarch64-linux-gdb out.elf

步骤3:在主机 GDB 控制台下建立与目标板的连接

bash 复制代码
(gdb) target remote 192.168.110.125:2345
# <target>:目标板的IP地址
# <port>:gdbserver 监听的网络端口号

自动化连接: 可以将 target remote 命令写入 .gdbinit 配置文件,启动 GDB 时会自动读取:

bash 复制代码
# .gdbinit 文件内容
target remote 192.168.110.125:2345

gdbserver 常用选项:

选项 说明 示例
--attach 附加到已运行的进程 gdbserver :2345 --attach 1234
--multi 多进程模式,允许调试多个进程 gdbserver --multi :2345
--once 调试完一个程序后自动退出 gdbserver --once :2345 ./program
--remote-debug 显示远程调试协议信息 gdbserver --remote-debug :2345 ./program

5.1.4 Coredump调试(事后崩溃分析)

Coredump(核心转储)是程序崩溃时操作系统将进程内存映像保存到文件的机制,用于事后分析崩溃原因。

配置 coredump:

bash 复制代码
# 查看当前 coredump 设置
$ ulimit -a

# 关闭 coredump
$ ulimit -c 0

# 设置 coredump 大小限制(单位:KB)
$ ulimit -c <num>

# 生成 coredump 文件大小没有限制(推荐)
$ ulimit -c unlimited

指定 coredump 文件存放目录:

bash 复制代码
# 默认在程序执行的当前目录生成文件 core
# 通过 core_pattern 指定存放目录和文件名格式
$ echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

core_pattern 参数含义:

参数 含义
%e 程序文件名
%h 主机名
%p 所 dump 进程的进程 ID
%u 所 dump 进程的实际用户 ID
%g 所 dump 进程的实际组 ID
%t coredump 的时间戳
%s 导致本次 coredump 的信号
%% 单个 % 字符

注意事项:

注意点 说明
可移动磁盘 可能无法在可移动磁盘中生成 coredump
磁盘空间 需要确保目标目录有足够的磁盘空间
systemd 系统 使用 coredumpctl 管理(coredumpctl listcoredumpctl gdb <PID>
ulimit 继承 子进程继承父进程的 ulimit 设置

使用 GDB 加载 coredump:

bash 复制代码
# 方式1:直接加载
$ gdb <program> core

# 方式2:进入 gdb 后加载
$ gdb <program>
(gdb) core-file core

触发 coredump 的信号:

信号 触发方式 默认行为
SIGQUIT Ctrl-\ 终止进程并生成 coredump
SIGSEGV 段错误(访问非法内存) 终止进程并生成 coredump
SIGABRT 调用 abort() 终止进程并生成 coredump
SIGBUS 总线错误 终止进程并生成 coredump
SIGFPE 算术异常(如除零) 终止进程并生成 coredump
SIGILL 非法指令 终止进程并生成 coredump
SIGTRAP 断点/陷阱 终止进程并生成 coredump

5.1.5 启动方式对比总结

调试场景 启动命令 适用条件
本地调试可执行文件 gdb <program> 有可执行文件和源码
附加运行进程 gdb -p <pid>gdb <program> <pid> 进程正在运行
调试 coredump gdb <program> core 有 core 文件
远程交叉调试 aarch64-linux-gdb + target remote 有 gdbserver
仅加载符号表 gdb -s <file> 只需要符号信息
批处理模式 gdb -batch -ex "cmd" 自动化脚本

5.2 程序执行控制

本节介绍 GDB 中控制程序执行的核心命令,包括运行与停止、单步执行、执行到指定位置和函数调用。这些是调试过程中使用频率最高的命令。

5.2.1 运行与停止(run/start/continue/kill)

命令 简写 描述
help 查看命令的帮助。例如 help info 查看 info 的所有命令
file 指定要调试的可执行程序
load 将动态库加载入内存
kill 终止正在调试的可执行程序
make 在不退出 gdb 的情况下运行 make 工具
shell 在不退出 gdb 的情况下运行 shell 命令
run r 开始执行程序
start 运行到 main 函数暂停
continue c 继续执行程序
quit q 结束 gdb 调试任务,也可以 Ctrl+D

实战示例:

bash 复制代码
# 在 GDB 中重新加载程序
(gdb) file ./new_program

# 在 GDB 中运行 make(修改代码后无需退出)
(gdb) make

# 在 GDB 中运行 shell 命令
(gdb) shell ls -la

# 终止当前调试的程序(但保留 GDB 会话)
(gdb) kill

# 重新运行
(gdb) run

5.2.2 单步执行(next/step/nexti/stepi)

命令 简写 描述
next n 单步执行,不会进入函数内部(显示的代码是下一步将要执行的代码)
nexti ni 单步执行,不会进入函数内部(显示的指令是下一步将要执行的指令)
step s 单步执行,可以跟踪到函数内部
stepi si 单步执行,可以跟踪到函数内部(指令级)

next/stepnexti/stepi 的区别:

对比项 next / step nexti / stepi
操作粒度 源代码行 汇编指令
显示内容 下一步将要执行的源代码 下一步将要执行的机器指令
适用场景 常规调试 分析汇编级行为、优化问题
是否进入函数 next 不进入,step 进入 nexti 不进入,stepi 进入

数字前缀: snsini 等指令可以加数字表示执行多少次:

bash 复制代码
(gdb) n 4      # 执行 4 步 next
(gdb) s 10     # 执行 10 步 step
(gdb) c 4      # 继续执行,遇到 4 次断点后停止

易错点:

易错点 说明
next 在循环中 每次只执行一行循环体,需要多次按回车,此时用 until 更高效
step 进入无源码函数 如果函数没有调试信息,step 会跳过该函数
优化代码单步 -O2 编译的代码行号可能跳跃,建议用 -O0-Og

5.2.3 执行到指定位置(until/finish/return)

命令 简写 描述
until u 直到运行到比原内存地址更高的内存地址的指令处停止(常用于跳出循环)
until <line> u <line> 直到运行到当前文件 line 行处停止
finish fin 函数执行完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息
return 函数直接从当前返回
return <value> 改变程序流程,直接结束当前函数,并将指定值 value 返回

until 的典型使用场景: 在循环体内时,next 每次只执行一行,需要多次按回车。until 可以一次性执行到循环结束:

bash 复制代码
(gdb) u        # 执行到循环结束(地址更高的位置)
(gdb) u 50     # 执行到当前文件第 50 行

finishreturn 的区别:

对比项 finish return
执行方式 继续执行到函数自然返回 立即从当前位置返回
剩余代码 会执行完函数剩余代码 跳过剩余代码
返回值 函数实际返回值 可指定返回值
适用场景 想看到函数完整执行结果 想跳过函数剩余部分

5.2.4 函数调用(call/print调用函数)

命令 描述
call <func> 在当前位置执行所要运行的函数 func
p <func> 在当前位置执行所要运行的函数 func(print 也可以调用函数)
bash 复制代码
# 在断点处调用函数
(gdb) call printf("debug: i=%d\n", i)
(gdb) p malloc(1024)

注意事项:

注意点 说明
副作用 调用的函数会实际执行,可能修改程序状态
返回类型 如果函数返回 void,使用 call 而非 p
栈帧要求 某些函数调用需要有效的栈帧上下文

5.2.5 快捷键与运行参数

快捷键/命令 说明
Ctrl+C 主动暂停程序运行
Ctrl+D 退出 gdb(同 quit
直接回车 重复上一次命令
set args <arg1> <arg2> 设置运行参数
show args 查看运行参数
cd <dir> 切换工作目录
set environment <var>=<val> 设置环境变量
show environment 查看所有环境变量

5.2.6 执行控制命令速查对比表

需求 命令 说明
开始运行 run / start start 停在 main 入口
继续运行 continue 运行到下一个断点
单步(不进函数) next 逐行执行
单步(进入函数) step 跟踪进入函数
跳出循环 until 执行到循环结束
执行完当前函数 finish 运行到函数返回
立即返回 return <val> 跳过剩余代码
执行 N 步 n N / s N 数字前缀
暂停运行中程序 Ctrl+C 发送 SIGINT

5.3 断点与观察点

本节介绍 GDB 中设置和管理断点、观察点、捕捉点的方法。断点是调试的核心机制,能够在代码特定位置暂停程序执行,以便检查程序状态。

5.3.1 断点设置(break/tbreak)

命令 描述 示例
b 当前位置设置断点 b
b <line> 当前文件 line 行设置断点 b 100
b <file>:<line> 指定文件 line 行设置断点 b main.c:100
b <func> 指定函数 func 入口设置断点 b malloc
b <addr> 指定内存 addr 处设置断点 b *0x9000888a
b +<offset> 当前行号的后面的 offset 行设置断点 b +5
b -<offset> 当前行号的前面的 offset 行设置断点 b -3
b ... if <condition> 设置条件断点,在循环中使用非常方便 b 10 if i==3
tb ... 设置临时断点,到达后被自动删除,使用类似 break tb main

条件断点实战: 在循环中调试时,条件断点非常有用:

bash 复制代码
# 在第 10 行设置断点,仅当 i==3 时中断
(gdb) b 10 if i==3

# 在函数入口设置条件断点
(gdb) b myadd if a > 100

# 临时断点(到达一次后自动删除)
(gdb) tb main.c:50

# 在地址上设置断点(无源码时)
(gdb) b *0x0000000000401149

条件断点支持的表达式:

表达式类型 示例 说明
简单比较 i == 10 等于
范围判断 i >= 5 && i <= 10 逻辑与
指针判断 ptr != 0 非空
字符串比较 strcmp(name, "test") == 0 调用函数
结构体成员 node->val > 100 成员访问

5.3.2 观察点(watch/rwatch/awatch)

命令 描述
watch <val> 设置观察点,指定 val 变量的值被软件改变后程序被暂停
watch <expr> 设置观察点,指定 expr 表达式的值被软件改变后程序被暂停
watch *<addr> 设置观察点,指定 addr 内存的值被软件改变后程序被暂停
awatch <val> 设置观察点,指定 val 变量被读出或写入时程序被暂停
rwatch <val> 设置观察点,指定 val 变量被读出时程序被暂停
twatch 设置临时观察点

观察点注意事项:

注意点 说明
作用域 watch 局部变量退出局部作用域会自动删除观察点
检测限制 GDB 无法检测一个非当前进程或硬件对表达式值的改变
硬件限制 硬件观察点数量有限(x86 通常 4 个),超出后使用软件观察点
性能影响 软件观察点性能开销极大(每步都检查),硬件观察点开销小

观察点对比表:

命令 触发条件 典型用途
watch 变量值被写入(改变) 追踪谁修改了某个变量
rwatch 变量被读取 追踪谁读取了某个变量
awatch 变量被读取或写入 追踪对变量的所有访问

实战示例:

bash 复制代码
# 监控变量 counter 的修改
(gdb) watch counter
Hardware watchpoint 2: counter

# 监控内存地址的写入
(gdb) watch *(int *)0x7fffffffe000

# 监控数组元素
(gdb) watch buf[5]

# 监控表达式
(gdb) watch x + y

5.3.3 捕捉点(catch/tcatch)

命令 描述
catch 设置捕捉点,来捕捉程序运行时的一些事件,如:载入共享库(动态链接库)或是 C++ 的异常
tcatch 只设置一次捕捉点,当程序停住以后,捕捉点被自动删除
bash 复制代码
# 捕捉共享库加载事件
(gdb) catch load libfoo.so

# 捕捉 C++ 异常
(gdb) catch throw

# 捕捉系统调用
(gdb) catch syscall open

# 捕捉 fork 事件
(gdb) catch fork

# 捕捉 exec 事件
(gdb) catch exec

常用捕捉事件:

事件 命令 说明
共享库加载 catch load [libname] 动态库加载时中断
C++ throw catch throw 抛出异常时中断
C++ catch catch catch 捕获异常时中断
系统调用 catch syscall [name] 特定系统调用时中断
fork catch fork 创建子进程时中断
exec catch exec 执行新程序时中断
信号 catch signal SIGSEGV 收到特定信号时中断

5.3.4 断点管理(info/delete/disable/enable/ignore)

命令 描述
i b 显示所有断点和观察点
clear <line> 清除指定 line 行的断点或观察点
d 清除所有断点和观察点
d <num> 清除指定 num 编号的断点或观察点
dis 所有断点和观察点失效
dis <num> 指定 num 编号的断点或观察点失效,可将编号之间用空格隔开
en 所有断点和观察点使能
en <num> 指定 num 编号的断点或观察点使能,可将编号之间用空格隔开
en once <num> 指定 num 编号的断点或观察点暂时使能一次
ignore <num> <times> 指定 num 编号的断点或观察点到达后不停止 times 次

实践示例:

bash 复制代码
# 查看所有断点
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000001139 in main at main.c:10
        breakpoint already hit 3 times
2       watchpoint     keep y                      counter

# 禁用断点 1
(gdb) disable 1

# 启用断点 1
(gdb) enable 1

# 暂时使能一次(触发后自动禁用)
(gdb) enable once 2

# 忽略断点 1 的前 5 次触发
(gdb) ignore 1 5

# 删除断点 1
(gdb) delete 1

# 删除所有断点
(gdb) delete

输出解读(info breakpoints):

字段 说明
Num 断点编号,用于 delete/disable/enable 等操作
Type 类型:breakpoint / watchpoint / catchpoint
Disp disposition:keep(保留)/ del(触发后删除)
Enb 是否启用:y / n
Address 断点地址
What 断点位置描述(文件:行号 或 函数名)
already hit N times 已触发次数

5.3.5 断点与观察点区别对比表

特性 断点(Breakpoint) 观察点(Watchpoint)
触发时机 CPU 到某一地址取指令时中断 CPU 到某一地址读写数据时中断
作用对象 代码地址(函数、行号) 内存地址/变量
生命周期 持久(除非手动删除) 局部变量退出作用域自动删除
硬件支持 通常由软件实现(修改指令) 可能需要硬件调试寄存器支持
性能影响 较小 可能较大(软件实现时)
操作通用性 所有使用于 breakpoint 的操作都适用于 watchpoint 同左
数量限制 无限制 硬件观察点有限(x86 通常 4 个)

5.4 数据查看与修改

本节介绍 GDB 中查看和修改程序数据的方法,包括内存查看、变量打印、自动显示、变量修改和类型查看。这些命令帮助开发者在程序暂停时深入理解程序状态。

5.4.1 内存查看(x命令)

语法: x /<数量><大小类型><显示类型> <内存地址>

大小类型:

字母 大小 说明
b 1 字节 byte
h 2 字节 halfword
w 4 字节 word(默认)
g 8 字节 giant

显示类型:

字母 格式 说明
o 八进制 octal
x 十六进制 hex(默认)
d 十进制 decimal
u 无符号十进制 unsigned decimal
t 二进制 binary
f 浮点数 float
a 地址 address
i 指令 instruction
c 字符 char
s 字符串 string
z 十六进制(左侧补零) hex, zero padded

示例:

bash 复制代码
# 以四字节为单位十六进制显示 0x90a2a7a0 开始的 64 个数据(默认大小 w)
(gdb) x /64x 0x90a2a7a0

# 以单字节为单位十六进制显示 64 个数据
(gdb) x /64bx 0x90a2a7a0

# 以八字节为单位十进制显示 10 个数据
(gdb) x /10gd 0x7fffffffe000

# 显示当前 PC 指针开始的 8 条指令
(gdb) x /8i $pc

# 以字符串形式显示
(gdb) x /s 0x4005d0

# 以字符形式显示 16 个字节
(gdb) x /16cb 0x7fffffffe000

输出解读(x /4xw $rsp):

复制代码
0x7fffffffe000: 0x00000003  0x00000005  0x00000000  0x00007fff
部分 含义
0x7fffffffe000 起始内存地址
0x00000003 该地址处的 4 字节数据(十六进制)
每行 4 个 默认每行显示 4 个单位

常用寄存器作为地址:

寄存器 含义 典型用法
$pc 程序计数器 x /10i $pc(查看当前指令)
$sp / $rsp 栈指针 x /16xg $rsp(查看栈内容)
$fp / $rbp 帧指针 x /8xg $fp(查看当前栈帧)
$lr / $ra 返回地址 x /1i $lr(查看返回指令)

5.4.2 变量打印(print命令)

命令 描述
p <var or expr> 打印变量或表达式的值,如 p a+b
p /<type> <var or expr> 指定格式打印,如 p /x a+b
p *<ptr>@<len> 显示数组值,如 p *buf@sizeof(buf)
p '<file>'::<var> 显示特定文件 file 的变量值,如 p 'file1.c'::var1
p '<func>'::<var> 显示特定函数 func 的变量值,如 p 'func1'::var1
p <var>=<value> 改变变量或表达式的值,如 p i=3

显示格式同 x 命令的显示类型(o/x/d/u/t/f/a/i/c/s/z)。

实践示例:

bash 复制代码
# 打印变量
(gdb) p counter
$1 = 42

# 十六进制打印
(gdb) p /x counter
$2 = 0x2a

# 打印表达式
(gdb) p a + b * 2
$3 = 100

# 打印数组内容(ptr 指向数组首地址,len 为元素个数)
(gdb) p *buf@sizeof(buf)
$4 = {0, 1, 2, 3, 4, 5, 6, 7}

# 打印特定文件中的静态变量
(gdb) p 'file1.c'::static_var

# 打印特定函数中的局部变量(需要停在该函数内)
(gdb) p 'myadd'::a

# 修改变量值
(gdb) p i = 100

print 输出格式说明:

前缀 含义
$1 第 1 次 print 的结果编号,可用 $1 引用
$2 第 2 次 print 的结果编号
$$ 上一次 print 的结果
$$2 倒数第 2 次 print 的结果

5.4.3 自动显示(display)

display 命令设置程序每次暂停后自动显示的数据及其格式,非常适合持续监控某个变量的变化。

命令 描述
disp <var or expr> 增加 display 用于显示变量或表达式的值,每当程序运行到断点处都会显示
disp /<type> <var or expr> 指定格式输出显示,如 disp /c str
disp /i $pc 自动显示下一条汇编指令($pc 表示指令地址,/i 表示输出格式为机器指令码)
i disp 显示当前所有的 display
undisp <num> 删除指定 num 编号的 display
d disp <num> 删除指定 num 编号的 display
dis disp <num> 指定 num 编号的 display 失效
en disp <num> 指定 num 编号的 display 使能
bash 复制代码
# 每次断点停止时自动显示变量 i 的值
(gdb) display i

# 以十六进制格式自动显示
(gdb) display /x flags

# 自动显示下一条汇编指令(单步调试汇编时非常有用)
(gdb) display /i $pc

# 查看所有 display
(gdb) info display

# 删除编号为 1 的 display
(gdb) undisplay 1

5.4.4 变量修改(set命令)

命令 描述
set <var>=<value> 改变变量或表达式的值,如 set i=3
p <var>=<value> 打印并改变变量值,如 p i=3

set 与 p 修改变量的区别:

对比项 set var=val p var=val
输出 不打印结果 打印修改后的值
用途 纯粹修改变量 修改并确认值
表达式 支持 支持

5.4.5 GDB自定义变量(convenience variables)

bash 复制代码
# 定义 GDB 调试环境中的自定义变量
# 第 1 次使用时会创建这个变量,后面再使用则直接对其赋值
(gdb) set $i=0
(gdb) set $i=$i+1
(gdb) p $i
$1 = 1

# 查看当前所设置的所有的环境变量(自定义变量)
(gdb) show convenience
$i = 1

自定义变量的用途:

用途 示例
计数器 set $count = $count + 1
保存地址 set $ptr = &my_struct
条件断点中使用 b main if $count > 10
与断点命令配合 在断点命令中累加计数

5.4.6 类型查看(whatis/ptype)

命令 描述
whatis <val> 显示变量 val 的数据类型
ptype <val> 显示变量的详细类型(包括结构体成员)
bash 复制代码
(gdb) whatis counter
type = int

(gdb) ptype my_struct
type = struct {
    int x;
    int y;
    char name[32];
}

whatis 与 ptype 的区别:

对比项 whatis ptype
输出详细度 仅显示类型名 显示完整类型定义
结构体 type = struct my_struct 显示所有成员及类型
适用场景 快速确认类型 查看结构体布局

5.4.7 结构体显示(set print pretty)

bash 复制代码
# 改变 struct 显示格式为多行显示(更易读)
(gdb) set print pretty on

对比效果:

bash 复制代码
# 关闭前:
$1 = {x = 1, y = 2, name = "test", data = {1, 2, 3}}

# 开启后:
$1 = {
  x = 1,
  y = 2,
  name = "test",
  data = {1, 2, 3}
}

其他打印格式设置:

命令 说明
set print pretty on 结构体多行显示
set print array on 数组多行显示
set print array-indexes on 数组显示下标
set print elements <N> 设置数组/字符串最大显示元素数(0=无限)
set print null-stop on 字符串遇到 NULL 停止显示
set print object on 显示 C++ 对象的实际类型
set print vtbl on 显示虚函数表

5.4.8 数据查看命令速查对比表

需求 命令 示例
查看内存 x /<fmt> <addr> x /16xw $rsp
打印变量 p <var> p counter
打印数组 p *ptr@len p *buf@10
自动显示 display <var> display i
修改变量 set var=val set i=100
查看类型 whatis / ptype ptype my_struct
自定义变量 set $var=val set $i=0

5.5 堆栈分析

程序的"调用堆栈"是当前函数之前的所有已调用函数的列表(包括当前函数)。每个函数及其变量都被分配了一个"帧"(frame),最近调用的函数在 0 号帧中("底部"帧)。
#mermaid-svg-PHBsaM8iILOfD3Xb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PHBsaM8iILOfD3Xb .error-icon{fill:#552222;}#mermaid-svg-PHBsaM8iILOfD3Xb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PHBsaM8iILOfD3Xb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PHBsaM8iILOfD3Xb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PHBsaM8iILOfD3Xb .marker.cross{stroke:#333333;}#mermaid-svg-PHBsaM8iILOfD3Xb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PHBsaM8iILOfD3Xb p{margin:0;}#mermaid-svg-PHBsaM8iILOfD3Xb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb .cluster-label text{fill:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb .cluster-label span{color:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb .cluster-label span p{background-color:transparent;}#mermaid-svg-PHBsaM8iILOfD3Xb .label text,#mermaid-svg-PHBsaM8iILOfD3Xb span{fill:#333;color:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb .node rect,#mermaid-svg-PHBsaM8iILOfD3Xb .node circle,#mermaid-svg-PHBsaM8iILOfD3Xb .node ellipse,#mermaid-svg-PHBsaM8iILOfD3Xb .node polygon,#mermaid-svg-PHBsaM8iILOfD3Xb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PHBsaM8iILOfD3Xb .rough-node .label text,#mermaid-svg-PHBsaM8iILOfD3Xb .node .label text,#mermaid-svg-PHBsaM8iILOfD3Xb .image-shape .label,#mermaid-svg-PHBsaM8iILOfD3Xb .icon-shape .label{text-anchor:middle;}#mermaid-svg-PHBsaM8iILOfD3Xb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PHBsaM8iILOfD3Xb .rough-node .label,#mermaid-svg-PHBsaM8iILOfD3Xb .node .label,#mermaid-svg-PHBsaM8iILOfD3Xb .image-shape .label,#mermaid-svg-PHBsaM8iILOfD3Xb .icon-shape .label{text-align:center;}#mermaid-svg-PHBsaM8iILOfD3Xb .node.clickable{cursor:pointer;}#mermaid-svg-PHBsaM8iILOfD3Xb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PHBsaM8iILOfD3Xb .arrowheadPath{fill:#333333;}#mermaid-svg-PHBsaM8iILOfD3Xb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PHBsaM8iILOfD3Xb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PHBsaM8iILOfD3Xb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PHBsaM8iILOfD3Xb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PHBsaM8iILOfD3Xb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PHBsaM8iILOfD3Xb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PHBsaM8iILOfD3Xb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PHBsaM8iILOfD3Xb .cluster text{fill:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb .cluster span{color:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PHBsaM8iILOfD3Xb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PHBsaM8iILOfD3Xb rect.text{fill:none;stroke-width:0;}#mermaid-svg-PHBsaM8iILOfD3Xb .icon-shape,#mermaid-svg-PHBsaM8iILOfD3Xb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PHBsaM8iILOfD3Xb .icon-shape p,#mermaid-svg-PHBsaM8iILOfD3Xb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PHBsaM8iILOfD3Xb .icon-shape .label rect,#mermaid-svg-PHBsaM8iILOfD3Xb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PHBsaM8iILOfD3Xb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PHBsaM8iILOfD3Xb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PHBsaM8iILOfD3Xb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} #0 帧:当前函数

(最近调用)
#1 帧:调用者
#2 帧:更上层调用者
...
#N 帧:main 函数

(最早调用)

5.5.1 栈帧查看(backtrace/bt)

命令 描述
bt 打印栈帧,查看程序执行到此时函数调用层次是怎样的
bt full 显示详细栈帧(包含每帧的局部变量)
bt <num> 显示前 num 层栈帧
bt -<num> 显示最后 num 层栈帧
bash 复制代码
(gdb) bt
#0  mydiv (a=3, b=0) at myop.c:16
#1  0x00000000000011a5 in main (argc=3, argv=0x7fffffffe1a8) at main.c:15

(gdb) bt full
#0  mydiv (a=3, b=0) at myop.c:16
        result = 0
#1  0x00000000000011a5 in main (argc=3, argv=0x7fffffffe1a8) at main.c:15
        a = 3
        b = 0

输出解读:

字段 说明
#0 帧编号,0 为最内层(当前函数)
mydiv (a=3, b=0) 函数名和参数值
at myop.c:16 源文件和行号
0x00000000000011a5 函数调用地址

5.5.2 栈帧切换(frame/up/down)

命令 描述
f <num> / frame <num> 切换到第 num 层栈
up 切换到高一层栈(调用者方向)
down 切换到低一层栈(被调用者方向)
bash 复制代码
(gdb) bt
#0  helper (x=10) at utils.c:25
#1  0x... in process (data=0x...) at main.c:42
#2  0x... in main () at main.c:60

# 切换到第 1 帧(process 函数)
(gdb) frame 1

# 向上切换一帧(到 main)
(gdb) up

# 向下切换一帧(回到 process)
(gdb) down

切换栈帧后的操作: 切换栈帧后,info localsinfo argsp 等命令都作用于当前帧。

5.5.3 栈信息查看(info stack/registers/frame)

命令 全称 描述
i s info stack 查看堆栈使用情况(同 bt
i r info registers 查看寄存器使用情况
i f info frame 查看当前栈层的详细信息(函数地址、调用函数的地址、被调用函数的地址等)

info frame 输出解读:

bash 复制代码
(gdb) info frame
Stack level 0, frame at 0x7fffffffe020:
 rip = 0x401149 in mydiv (myop.c:16); saved rip = 0x4011a5
 called by frame at 0x7fffffffe040
 source language c.
 Arglist at 0x7fffffffe010, args: a=3, b=0
 Locals at 0x7fffffffe010, Previous frame's sp is 0x7fffffffe020
 Saved registers:
  rbp at 0x7fffffffe010, rip at 0x7fffffffe018
字段 说明
Stack level 栈层级
frame at 帧地址
rip 当前指令地址
saved rip 返回地址
called by frame at 调用者帧地址
Arglist 参数列表地址
Locals 局部变量地址
Saved registers 保存的寄存器

5.5.4 函数参数与局部变量(info args/locals)

命令 描述
i args 查看当前函数的参数名及其值
i locals 查看当前函数中所有局部变量及其值
i catch 查看当前函数中的异常处理信息
bash 复制代码
(gdb) info args
a = 3
b = 5

(gdb) info locals
result = 8
temp = 0

5.5.5 堆栈分析命令速查表

需求 命令 说明
查看完整调用栈 bt 最常用
查看含局部变量的栈 bt full 信息更全
只看前 N 层 bt N 栈很深时有用
切换栈帧 frame N / up / down 查看不同层的变量
查看当前帧详情 info frame 地址、寄存器
查看函数参数 info args 当前帧的参数
查看局部变量 info locals 当前帧的局部变量
查看寄存器 info registers 所有寄存器值

5.6 多线程调试

本节介绍 GDB 中多线程程序的调试方法,包括线程查看与切换、线程断点、批量命令执行和调度锁定。多线程调试是并发编程问题排查的核心技能。

5.6.1 线程查看与切换(info threads/thread)

命令 描述
info threads 查看所有线程信息。GDB 会为每个线程分配一个 ID(和系统 TID 不同),编号一般从 1 开始
thread <ID> 切换当前调试的线程为指定 ID 的线程
bash 复制代码
(gdb) info threads
  Id   Target Id                                 Frame
* 1    Thread 0x7ffff7... (LWP 12345) "program" main () at main.c:10
  2    Thread 0x7ffff6... (LWP 12346) "program" worker () at worker.c:25
  3    Thread 0x7ffff5... (LWP 12347) "program" 0x00007ffff7... in pthread_cond_wait ()

# 切换到线程 2
(gdb) thread 2

输出解读:

字段 说明
* 标记当前正在调试的线程
Id GDB 内部线程编号(从 1 开始)
Target Id 系统级线程标识(LWP = Light Weight Process)
Frame 线程当前停止的位置

注意: info threads 输出中的 * 标记表示当前正在调试的线程。

5.6.2 线程断点(thread all/thread N)

bash 复制代码
# 所有线程都在文件 file 的第 line 行有断点
(gdb) b <file>:<line> thread all
(gdb) b malloc.c:128 thread all

# 仅在特定线程设置断点
(gdb) b main.c:50 thread 2

线程断点与普通断点的区别:

对比项 普通断点 线程断点
触发线程 任何线程到达都触发 仅指定线程触发
语法 b main.c:50 b main.c:50 thread 2
适用场景 通用 只关注特定线程的行为

5.6.3 线程命令批量执行(thread apply)

命令 描述
thread apply <ID1> <ID2> ... <command> 多个线程执行 gdb 命令 command
thread apply all <command> 所有线程执行 gdb 命令 command
bash 复制代码
# 查看所有线程的堆栈(多线程死锁调试必备)
(gdb) thread apply all bt

# 对线程 1 和 3 执行命令
(gdb) thread apply 1 3 info locals

5.6.4 调度锁定(set scheduler-locking)

命令 说明
set scheduler-locking off 不锁定任何线程(默认值)
set scheduler-locking on 锁定其他线程,只有当前线程执行
set scheduler-locking step 在 step(单步)时,只有被调试线程运行

各模式对比:

模式 next / step 时 continue 时 适用场景
off 所有线程都可能运行 所有线程运行 默认,观察多线程交互
on 只有当前线程运行 只有当前线程运行 严格单线程调试
step 只有当前线程运行 所有线程运行 单步时隔离,继续时恢复

实战建议:

场景 推荐模式
调试单线程逻辑 on
观察多线程竞争 off
单步跟踪特定线程 step
死锁分析 off(需要所有线程运行到死锁状态)

5.6.5 多线程调试选项

命令 说明
set non-stop on/off 在调试某一个线程时,其他线程是否运行
set pagination on/off 在使用 backtrace 时,在分页时是否停止
set target-async on/off 同步和异步。同步:gdb 在输出提示符之前等待程序报告一些线程已经终止的信息;异步:直接返回
set print thread-events on/off 线程创建/销毁是否提醒

5.6.6 多线程调试命令速查表

需求 命令 说明
查看所有线程 info threads 显示线程状态
切换线程 thread N N 为 GDB 线程 ID
所有线程堆栈 thread apply all bt 死锁分析必备
线程断点 b <loc> thread N 仅特定线程触发
锁定调度 set scheduler-locking on 隔离调试
关闭线程事件提示 set print thread-events off 减少干扰

5.7 多进程调试

本节介绍 GDB 中多进程程序的调试方法,包括进程挂接、fork 跟踪、进程列表与切换和进程管理。

5.7.1 进程挂接(attach/detach)

命令 描述
attach <pid> 挂接进程
detach 取消挂接的进程

5.7.2 fork跟踪(set follow-fork-mode)

命令 说明
set follow-fork-mode parent fork 创建子进程时,调试父进程(默认)
set follow-fork-mode child fork 创建子进程时,调试子进程
bash 复制代码
# 调试 fork 后的子进程
(gdb) set follow-fork-mode child
(gdb) run

fork 调试模式对比:

模式 fork 后调试 另一个进程 适用场景
parent 父进程 子进程继续运行 调试父进程逻辑
child 子进程 父进程继续运行 调试子进程逻辑

5.7.3 进程列表与切换(info inferiors/inferior)

命令 描述
info inferiors 查看当前正在调试的所有进程列表
inferior <ID> 切换到指定 ID 的进程进行调试
bash 复制代码
(gdb) info inferiors
  Num  Description       Executable
* 1    process 12345     ./program
  2    process 12346     ./program

(gdb) inferior 2

5.7.4 进程管理(add-inferior/remove-inferiors/clone-inferior)

命令 描述
add-inferior 添加一个新的待调试进程
remove-inferiors <ID> 移除指定 ID 的进程(从调试列表中移除,不终止进程)
clone-inferior 克隆当前进程创建一个新的调试进程

5.7.5 进程内存信息(maint info sections)

命令 描述
maint info sections 显示当前进程的内存段信息

注意: 每个进程有自己的地址空间,断点和观察点是进程特定的。

5.7.6 多进程调试命令速查表

需求 命令 说明
附加进程 attach <pid> 挂接运行中进程
分离进程 detach 取消挂接
fork 跟踪子进程 set follow-fork-mode child 调试子进程
查看所有进程 info inferiors 进程列表
切换进程 inferior N 切换调试目标
查看内存段 maint info sections 进程内存布局

5.8 信号处理

本节介绍 GDB 中信号的处理方式,包括向被调试程序发送信号和控制 GDB 对信号的拦截行为。

5.8.1 信号发送与处理(signal/handle)

命令 描述
signal <num> 发送一个信号量给被调试的程序
handle <signal> nostop 忽略信号处理(GDB 不拦截该信号)
bash 复制代码
# 忽略 SIGPIPE 信号(网络编程中常用)
(gdb) handle SIGPIPE nostop

# 发送 SIGINT 信号给被调试程序
(gdb) signal 2

# 查看当前信号处理设置
(gdb) info handle

5.8.2 handle命令选项详解

handle 命令的常用选项组合:

选项 说明
nostop GDB 不拦截该信号,直接传递给程序
stop GDB 拦截该信号并暂停程序(默认)
pass / noignore 将信号传递给被调试程序
nopass / ignore 不将信号传递给被调试程序
print 收到信号时打印信息(默认)
noprint 收到信号时不打印信息

选项组合效果对比:

组合 GDB 行为 程序行为 典型场景
stop print pass 暂停并显示 收到信号 默认行为
nostop noprint pass 不干预 正常处理 忽略高频信号(如 SIGPIPE)
stop print nopass 暂停并显示 不收到信号 屏蔽特定信号
nostop noprint nopass 完全忽略 不收到信号 彻底屏蔽

实战示例:

bash 复制代码
# 网络编程中忽略 SIGPIPE(连接断开时不中断调试)
(gdb) handle SIGPIPE nostop noprint pass

# 屏蔽 SIGCHLD(避免子进程退出干扰)
(gdb) handle SIGCHLD nostop noprint pass

# 查看 SIGSEGV 的处理设置
(gdb) info handle SIGSEGV
Signal        Stop      Print   Pass to program Description
SIGSEGV       Yes       Yes     Yes             Segmentation fault

5.8.3 常见信号与调试关系

信号 编号 含义 调试中的处理
SIGINT 2 中断(Ctrl+C) 用于暂停程序
SIGSEGV 11 段错误 定位崩溃位置
SIGABRT 6 异常终止 assert 失败、abort()
SIGPIPE 13 管道断裂 网络编程中常忽略
SIGCHLD 17 子进程状态变化 多进程调试中常忽略
SIGUSR1/2 10/12 用户自定义信号 可用于调试触发

5.9 源码与反汇编查看

本节介绍 GDB 中查看源代码和反汇编代码的方法,以及 TUI 窗口模式的使用。

5.9.1 源码列表(list命令)

命令 说明
list / l 部分列出源代码(当前位置附近)
l <line> 列出指定行附近的源代码
l <func> 列出指定函数附近的源代码
l <file>:<line> 列出指定文件指定行附近的源代码
l <start>,<end> 列出从 start 到 end 行的源代码
bash 复制代码
# 列出当前位置附近的源码(默认 10 行)
(gdb) list

# 列出 main 函数附近的源码
(gdb) list main

# 列出指定文件的指定行
(gdb) list main.c:50

# 列出第 10 到第 30 行
(gdb) list 10,30

# 设置每次显示的行数
(gdb) set listsize 20

5.9.2 反汇编(disassemble命令)

命令 说明
disassemble / disas 反汇编当前函数
disas <func> 反汇编指定函数
disas <addr> 反汇编指定地址
disas /m <func> 混合源码和汇编
disas /r <func> 显示原始机器码
bash 复制代码
# 反汇编当前函数
(gdb) disas

# 反汇编指定函数
(gdb) disas myadd

# 混合源码和汇编(需要 -g 编译)
(gdb) disas /m myadd

# 反汇编指定地址范围
(gdb) disas 0x401149, 0x4011a5

输出解读(disas /m):

复制代码
Dump of assembler code for function myadd:
4       int myadd(int a, int b) {
   0x0000000000001129 <+0>:     push   %rbp
   0x000000000000112a <+1>:     mov    %rsp,%rbp
5           return a + b;
   0x000000000000112d <+4>:     mov    %edi,-0x4(%rbp)
   0x0000000000001130 <+7>:     mov    %esi,-0x8(%rbp)
   0x0000000000001133 <+10>:    mov    -0x4(%rbp),%eax
   0x0000000000001136 <+13>:    add    -0x8(%rbp),%eax
6       }
   0x0000000000001139 <+16>:    pop    %rbp
   0x000000000000113a <+17>:    ret

5.9.3 窗口模式(TUI)

命令 描述
layout 用于分割窗口,可以一边查看代码,一边测试
layout src 显示源代码窗口
layout asm 显示反汇编窗口
layout regs 显示源代码/反汇编和 CPU 寄存器窗口
layout split 显示源代码和反汇编窗口
Ctrl + L 刷新窗口
tui enable 启用 TUI 模式
tui disable 禁用 TUI 模式

TUI 布局对比:

布局命令 上半窗口 下半窗口 适用场景
layout src 源代码 GDB 命令 常规源码调试
layout asm 反汇编 GDB 命令 汇编级调试
layout split 源代码 反汇编 对照源码和汇编
layout regs 源码/汇编 寄存器 查看寄存器变化

启动 TUI 的方式:

bash 复制代码
# 方式1:启动时进入 TUI
$ gdb -tui ./program

# 方式2:在 GDB 中切换
(gdb) tui enable

# 方式3:快捷键
Ctrl+X, Ctrl+A    # 切换 TUI 模式
Ctrl+X, 1         # 单窗口
Ctrl+X, 2         # 双窗口

5.10 自定义命令与脚本

本节介绍 GDB 中自定义命令的语法和用法,以及内存导出和核心转储文件的生成。自定义命令可以显著提升重复性调试操作的效率。

5.10.1 define/document语法(自定义命令)

自定义命令:

复制代码
define 命令名
    命令
    ...
end

自定义命令说明:

复制代码
document 命令名
    命令说明
    ...
end

5.10.2 自定义命令示例

bash 复制代码
# 定义一个显示当前 PC 开始 8 条指令的命令
(gdb) define li
>x /8i $pc
>end

# 添加命令说明
(gdb) document li
>显示当前地址开始的 8 条指令
>end

# 使用自定义命令
(gdb) li

更多自定义命令示例:

bash 复制代码
# 定义显示当前栈帧完整信息的命令
(gdb) define fi
>info frame
>info args
>info locals
>end

# 定义显示所有线程堆栈的命令
(gdb) define allbt
>thread apply all bt
>end

# 定义带参数的命令($arg0, $arg1...)
(gdb) define hexdump
>x /$arg0xw $arg1
>end
# 使用:hexdump 16 $rsp

5.10.3 dump内存(导出内存到文件)

bash 复制代码
# 将内存内容导出到文件
(gdb) dump memory file.log start_addr end_addr

# 示例:导出 0x1000 到 0x2000 的内存内容
(gdb) dump memory /tmp/mem_dump.bin 0x1000 0x2000

# 导出特定变量所在内存
(gdb) dump memory /tmp/var_dump.bin &my_struct &my_struct+sizeof(my_struct)

dump 命令的其他形式:

命令 说明
dump memory <file> <start> <end> 导出原始内存
dump ihex memory <file> <start> <end> Intel HEX 格式
dump srec memory <file> <start> <end> S-record 格式
dump verilog memory <file> <start> <end> Verilog 格式

5.10.4 generate-core-file(生成核心转储)

bash 复制代码
# 生成内核转储文件(查看调试历史、保存当前调试状态)
(gdb) generate-core-file
Saved corefile core.12345

用途:

场景 说明
保存调试现场 将当前程序状态保存为 core 文件,之后可重新加载分析
分享问题 将 core 文件发给同事协助分析
对比分析 在不同时间点生成 core 文件,对比状态变化

5.10.5 GDB Python脚本(高级自动化)

GDB 内置 Python 解释器,支持使用 Python 编写复杂的调试脚本和自定义命令。

基本用法:

bash 复制代码
# 在 GDB 中执行 Python 代码
(gdb) python print("Hello from Python")

# 执行 Python 脚本文件
(gdb) source my_script.py

# 多行 Python 代码
(gdb) python
>import gdb
>val = gdb.parse_and_eval("counter")
>print(f"counter = {val}")
>end

Python 自定义命令示例:

python 复制代码
# 文件:my_commands.py
import gdb

class PrintStructCmd(gdb.Command):
    """打印结构体成员及偏移"""
    def __init__(self):
        super().__init__("pstruct", gdb.COMMAND_USER)

    def invoke(self, arg, from_tty):
        val = gdb.parse_and_eval(arg)
        for field in val.type.fields():
            print(f"  offset {field.bitpos//8:3d}: {field.name} = {val[field.name]}")

PrintStructCmd()
bash 复制代码
# 加载并使用
(gdb) source my_commands.py
(gdb) pstruct my_struct

Python API 常用类:

类/函数 说明
gdb.Command 自定义命令基类
gdb.Breakpoint Python 断点(支持 stop 回调)
gdb.parse_and_eval() 解析并求值表达式
gdb.execute() 执行 GDB 命令
gdb.selected_frame() 获取当前栈帧
gdb.selected_inferior() 获取当前进程
gdb.lookup_symbol() 查找符号

5.10.6 命令文件(source命令)

bash 复制代码
# 将常用命令写入文件
$ cat debug_commands.gdb
b main
run
display i
display /x flags

# 在 GDB 中加载执行
(gdb) source debug_commands.gdb

# 或启动时通过 -x 加载
$ gdb -x debug_commands.gdb ./program

5.11 GDB命令速查总表

本节将 GDB 所有命令按功能分类汇总,方便快速查阅。

5.11.1 按功能分类汇总表

分类 命令 简写 说明
启动连接 gdb <program> 启动调试
gdb --pid <pid> 调试运行进程
gdb <program> core 调试 coredump
target remote <host>:<port> 远程调试
执行控制 run r 开始执行
start 运行到 main
continue c 继续执行
next n 单步(不进入函数)
step s 单步(进入函数)
nexti ni 指令级单步(不进入)
stepi si 指令级单步(进入)
until u 执行到指定位置
finish fin 执行到函数返回
return <value> 直接返回指定值
call <func> 调用函数
quit q 退出
断点 break b 设置断点
tbreak tb 临时断点
watch 写观察点
rwatch 读观察点
awatch 读写观察点
catch 捕捉点
delete d 删除断点
disable dis 禁用断点
enable en 启用断点
ignore <num> <times> 忽略断点
info breakpoints i b 查看断点
数据 print p 打印变量
x /<fmt> <addr> 查看内存
display disp 自动显示
undisplay undisp 删除自动显示
set <var>=<val> 设置变量
whatis 查看类型
ptype 查看详细类型
堆栈 backtrace bt 查看堆栈
bt full 详细堆栈
frame <num> f <num> 切换栈帧
up / down 上/下切换帧
info registers i r 查看寄存器
info frame i f 查看帧信息
info args i args 查看函数参数
info locals i locals 查看局部变量
线程 info threads 查看线程
thread <ID> 切换线程
thread apply all <cmd> 所有线程执行命令
set scheduler-locking 调度锁定
进程 info inferiors 查看进程
inferior <ID> 切换进程
attach / detach 挂接/分离进程
set follow-fork-mode fork 跟踪
信号 signal <num> 发送信号
handle <sig> nostop 设置信号处理
窗口 layout src/asm/regs/split TUI 布局
Ctrl+L 刷新窗口
自定义 define 定义命令
document 命令说明
dump memory 导出内存
generate-core-file 生成转储文件
反向调试 record 开始记录
reverse-step rs 反向单步
reverse-next rn 反向单步(不进函数)
reverse-continue rc 反向继续
reverse-finish 反向执行到函数入口

5.11.2 常用快捷键

快捷键 说明
Ctrl+C 主动暂停程序运行
Ctrl+D 退出 GDB(同 quit
直接回车 重复上一次命令
Ctrl+L 刷新 TUI 窗口
Ctrl+X, Ctrl+A 切换 TUI 模式
Ctrl+X, 1 TUI 单窗口
Ctrl+X, 2 TUI 双窗口

5.12 GDB调试完整流程示例

以下是一个完整的调试会话示例,综合运用本章介绍的各类命令:

bash 复制代码
# 编译(带调试信息)
$ gcc -O0 -g -ggdb -o myop main.c myop.c -lm

# 启动调试
$ gdb ./myop

# 设置运行参数并运行到 main
(gdb) set args 3 0
(gdb) start

# 在 mydiv 函数设置断点
(gdb) b mydiv

# 继续运行
(gdb) c

# 到达断点后查看堆栈
(gdb) bt
#0  mydiv (a=3, b=0) at myop.c:16
#1  0x... in main () at main.c:15

# 查看参数和局部变量
(gdb) info args
(gdb) info locals

# 查看内存
(gdb) x /4xw $rsp

# 修改变量值(绕过除零)
(gdb) set b=1

# 继续运行
(gdb) c

# 退出
(gdb) q

调试流程总结:
#mermaid-svg-ANcVE8P71LIRVhiM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ANcVE8P71LIRVhiM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ANcVE8P71LIRVhiM .error-icon{fill:#552222;}#mermaid-svg-ANcVE8P71LIRVhiM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ANcVE8P71LIRVhiM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ANcVE8P71LIRVhiM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ANcVE8P71LIRVhiM .marker.cross{stroke:#333333;}#mermaid-svg-ANcVE8P71LIRVhiM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ANcVE8P71LIRVhiM p{margin:0;}#mermaid-svg-ANcVE8P71LIRVhiM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ANcVE8P71LIRVhiM .cluster-label text{fill:#333;}#mermaid-svg-ANcVE8P71LIRVhiM .cluster-label span{color:#333;}#mermaid-svg-ANcVE8P71LIRVhiM .cluster-label span p{background-color:transparent;}#mermaid-svg-ANcVE8P71LIRVhiM .label text,#mermaid-svg-ANcVE8P71LIRVhiM span{fill:#333;color:#333;}#mermaid-svg-ANcVE8P71LIRVhiM .node rect,#mermaid-svg-ANcVE8P71LIRVhiM .node circle,#mermaid-svg-ANcVE8P71LIRVhiM .node ellipse,#mermaid-svg-ANcVE8P71LIRVhiM .node polygon,#mermaid-svg-ANcVE8P71LIRVhiM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ANcVE8P71LIRVhiM .rough-node .label text,#mermaid-svg-ANcVE8P71LIRVhiM .node .label text,#mermaid-svg-ANcVE8P71LIRVhiM .image-shape .label,#mermaid-svg-ANcVE8P71LIRVhiM .icon-shape .label{text-anchor:middle;}#mermaid-svg-ANcVE8P71LIRVhiM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ANcVE8P71LIRVhiM .rough-node .label,#mermaid-svg-ANcVE8P71LIRVhiM .node .label,#mermaid-svg-ANcVE8P71LIRVhiM .image-shape .label,#mermaid-svg-ANcVE8P71LIRVhiM .icon-shape .label{text-align:center;}#mermaid-svg-ANcVE8P71LIRVhiM .node.clickable{cursor:pointer;}#mermaid-svg-ANcVE8P71LIRVhiM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ANcVE8P71LIRVhiM .arrowheadPath{fill:#333333;}#mermaid-svg-ANcVE8P71LIRVhiM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ANcVE8P71LIRVhiM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ANcVE8P71LIRVhiM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ANcVE8P71LIRVhiM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ANcVE8P71LIRVhiM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ANcVE8P71LIRVhiM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ANcVE8P71LIRVhiM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ANcVE8P71LIRVhiM .cluster text{fill:#333;}#mermaid-svg-ANcVE8P71LIRVhiM .cluster span{color:#333;}#mermaid-svg-ANcVE8P71LIRVhiM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ANcVE8P71LIRVhiM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ANcVE8P71LIRVhiM rect.text{fill:none;stroke-width:0;}#mermaid-svg-ANcVE8P71LIRVhiM .icon-shape,#mermaid-svg-ANcVE8P71LIRVhiM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ANcVE8P71LIRVhiM .icon-shape p,#mermaid-svg-ANcVE8P71LIRVhiM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ANcVE8P71LIRVhiM .icon-shape .label rect,#mermaid-svg-ANcVE8P71LIRVhiM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ANcVE8P71LIRVhiM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ANcVE8P71LIRVhiM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ANcVE8P71LIRVhiM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是


崩溃
编译带调试信息
启动 GDB
设置参数/断点
运行程序
到达断点?
查看状态: bt/p/x
找到问题?
单步/继续
修改/验证
继续或退出
分析崩溃: bt/info frame

5.13 GDB调试实战场景

本节通过多个真实调试场景,展示如何综合运用 GDB 的各种功能解决实际开发中遇到的问题。

5.13.1 段错误调试(定位崩溃位置)

段错误(Segmentation Fault)是最常见的程序崩溃类型,通常由访问非法内存地址引起。GDB 可以精确定位段错误发生的位置和原因。

方法一:直接运行复现

bash 复制代码
$ gcc -O0 -g -ggdb -o program program.c
$ gdb ./program
(gdb) run
Starting program: /home/user/program

Program received signal SIGSEGV, Segmentation fault.
0x0000000000001149 in main () at main.c:6
6           *p = 'h';

# 查看崩溃时的堆栈
(gdb) bt
#0  0x0000000000001149 in main () at main.c:6

# 查看导致崩溃的变量
(gdb) p p
$1 = 0x402004 "Hello world!"

# 查看内存权限(只读段不可写)
(gdb) x /4xw p
0x402004:   0x6c6c6548  0x6f77206f  0x21646c72  0x00000000

方法二:通过 coredump 事后分析

bash 复制代码
# 确保 coredump 已开启
$ ulimit -c unlimited

# 运行程序触发崩溃
$ ./program
Segmentation fault (core dumped)

# 用 GDB 加载 coredump
$ gdb ./program core
(gdb) bt
#0  0x0000000000001149 in main () at main.c:6

方法三:结合 addr2line(无 GDB 环境时)

bash 复制代码
# 从 dmesg 获取出错地址
$ dmesg | tail -2
a.out[13275]: segfault at 491f44 ip 0000000000400b80 sp 00007ffecb47fd50 error 7

# 使用 addr2line 定位
$ addr2line -fap -e a.out 0x0000000000400b80
0x0000000000400b80: main at /home/user/main.c:6

段错误常见原因与排查:

原因 典型表现 排查方法
空指针解引用 访问地址为 0x0 或极小值 bt 查看堆栈,p 检查指针
野指针 访问已释放的内存 结合 ASan 或 valgrind
栈溢出 递归过深或大数组 bt 查看调用深度,info frame
写入只读段 修改字符串常量 x 查看内存地址所在段
数组越界 访问超出分配范围的地址 p 检查数组下标和大小

5.13.2 内存越界调试(watchpoint定位)

bash 复制代码
$ gdb ./program
(gdb) b main
(gdb) run

# 在可疑的数组操作处设置观察点
(gdb) watch buf[10]    # 假设 buf 大小为 10,监控越界写入

# 或者使用条件断点
(gdb) b loop_func if i >= ARRAY_SIZE

# 继续运行,观察何时越界
(gdb) c
Hardware watchpoint 2: buf[10]

Old value = 0
New value = 42
loop_func (i=10) at main.c:25

输出解读: 当观察点触发时,GDB 会显示旧值(Old value)和新值(New value),以及触发位置,从而精确定位越界写入的代码位置。

5.13.3 多线程死锁调试(thread apply all bt)

多线程死锁是并发编程中最难调试的问题之一。GDB 提供了完整的线程调试支持。

bash 复制代码
$ gdb ./program
(gdb) run

# 程序卡住后,按 Ctrl+C 中断
^C
Thread 1 "program" received signal SIGINT, Interrupt.

# 查看所有线程状态
(gdb) info threads
  Id   Target Id                                 Frame
* 1    Thread 0x7ffff7... (LWP 12345) "program" __lll_lock_wait ()
  2    Thread 0x7ffff6... (LWP 12346) "program" __lll_lock_wait ()
  3    Thread 0x7ffff5... (LWP 12347) "program" 0x... in pthread_cond_wait ()

# 查看所有线程的堆栈(死锁分析的核心命令)
(gdb) thread apply all bt

Thread 3 (Thread 0x7ffff5...):
#0  pthread_cond_wait ()
#1  worker_thread () at worker.c:45

Thread 2 (Thread 0x7ffff6...):
#0  __lll_lock_wait ()
#1  pthread_mutex_lock ()
#2  process_data () at process.c:30    ← 等待 mutex_b
#3  thread_func_b () at main.c:55

Thread 1 (Thread 0x7ffff7...):
#0  __lll_lock_wait ()
#1  pthread_mutex_lock ()
#2  process_data () at process.c:25    ← 等待 mutex_a
#3  thread_func_a () at main.c:40

死锁分析要点:

步骤 操作 目的
1 thread apply all bt 查看所有线程的调用栈
2 关注 __lll_lock_wait 确认哪些线程在等锁
3 查看各线程等待的锁 找出锁的持有者
4 对比持有和等待关系 找出循环依赖

死锁模式识别:
#mermaid-svg-2qHt1MpJS1yl5nqt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2qHt1MpJS1yl5nqt .error-icon{fill:#552222;}#mermaid-svg-2qHt1MpJS1yl5nqt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2qHt1MpJS1yl5nqt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2qHt1MpJS1yl5nqt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2qHt1MpJS1yl5nqt .marker.cross{stroke:#333333;}#mermaid-svg-2qHt1MpJS1yl5nqt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2qHt1MpJS1yl5nqt p{margin:0;}#mermaid-svg-2qHt1MpJS1yl5nqt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt .cluster-label text{fill:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt .cluster-label span{color:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt .cluster-label span p{background-color:transparent;}#mermaid-svg-2qHt1MpJS1yl5nqt .label text,#mermaid-svg-2qHt1MpJS1yl5nqt span{fill:#333;color:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt .node rect,#mermaid-svg-2qHt1MpJS1yl5nqt .node circle,#mermaid-svg-2qHt1MpJS1yl5nqt .node ellipse,#mermaid-svg-2qHt1MpJS1yl5nqt .node polygon,#mermaid-svg-2qHt1MpJS1yl5nqt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2qHt1MpJS1yl5nqt .rough-node .label text,#mermaid-svg-2qHt1MpJS1yl5nqt .node .label text,#mermaid-svg-2qHt1MpJS1yl5nqt .image-shape .label,#mermaid-svg-2qHt1MpJS1yl5nqt .icon-shape .label{text-anchor:middle;}#mermaid-svg-2qHt1MpJS1yl5nqt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2qHt1MpJS1yl5nqt .rough-node .label,#mermaid-svg-2qHt1MpJS1yl5nqt .node .label,#mermaid-svg-2qHt1MpJS1yl5nqt .image-shape .label,#mermaid-svg-2qHt1MpJS1yl5nqt .icon-shape .label{text-align:center;}#mermaid-svg-2qHt1MpJS1yl5nqt .node.clickable{cursor:pointer;}#mermaid-svg-2qHt1MpJS1yl5nqt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2qHt1MpJS1yl5nqt .arrowheadPath{fill:#333333;}#mermaid-svg-2qHt1MpJS1yl5nqt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2qHt1MpJS1yl5nqt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2qHt1MpJS1yl5nqt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2qHt1MpJS1yl5nqt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2qHt1MpJS1yl5nqt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2qHt1MpJS1yl5nqt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2qHt1MpJS1yl5nqt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2qHt1MpJS1yl5nqt .cluster text{fill:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt .cluster span{color:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2qHt1MpJS1yl5nqt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2qHt1MpJS1yl5nqt rect.text{fill:none;stroke-width:0;}#mermaid-svg-2qHt1MpJS1yl5nqt .icon-shape,#mermaid-svg-2qHt1MpJS1yl5nqt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2qHt1MpJS1yl5nqt .icon-shape p,#mermaid-svg-2qHt1MpJS1yl5nqt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2qHt1MpJS1yl5nqt .icon-shape .label rect,#mermaid-svg-2qHt1MpJS1yl5nqt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2qHt1MpJS1yl5nqt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2qHt1MpJS1yl5nqt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2qHt1MpJS1yl5nqt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线程1

持有 mutex_a

等待 mutex_b
mutex_b

被线程2持有
线程2

持有 mutex_b

等待 mutex_a
mutex_a

被线程1持有

5.13.4 条件断点调试循环(精确定位迭代)

在循环中调试时,条件断点可以精确定位到特定迭代:

bash 复制代码
(gdb) b process_item if i == 999
(gdb) run

# 到达第 999 次迭代时自动中断
Breakpoint 1, process_item (i=999) at main.c:42

# 查看此时的变量状态
(gdb) info locals
(gdb) p data[i]

# 也可以使用 ignore 跳过前 N 次
(gdb) b process_item
(gdb) ignore 1 998    # 前 998 次不停止
(gdb) c               # 第 999 次停止

条件断点 vs ignore 对比:

对比项 条件断点 ignore
语法 b <loc> if <cond> ignore <num> <times>
灵活性 支持任意表达式 只能跳过固定次数
性能 每次到达都检查条件 无额外开销
适用场景 复杂条件(如特定值) 简单跳过前 N 次

5.13.5 动态库调试(info sharedlibrary)

bash 复制代码
# 设置动态库搜索路径
(gdb) set environment LD_LIBRARY_PATH=./lib

# 在动态库函数中设置断点
(gdb) b myadd
(gdb) run

# 查看动态库加载信息
(gdb) info sharedlibrary
From        To          Syms Read   Shared Object Library
0x00007f... 0x00007f... Yes         ./libmyop.so
0x00007f... 0x00007f... Yes         /lib/x86_64-linux-gnu/libc.so.6

# 捕捉动态库加载事件
(gdb) catch load libmyop.so
(gdb) run

动态库调试常见问题:

问题 原因 解决方法
断点 PENDING 库尚未加载 set breakpoint pending on
找不到库 路径不对 set environment LD_LIBRARY_PATH=...
无符号 库被 strip 使用未 strip 的库或分离的调试信息

5.13.6 修改程序流程调试(验证假设)

GDB 允许在调试时修改程序执行流程和变量值,用于验证假设:

bash 复制代码
# 修改变量值(绕过某个条件)
(gdb) p flag = 1

# 直接返回指定值(跳过当前函数)
(gdb) return 0

# 跳转到指定行(跳过某段代码)
(gdb) jump 50

# 调用函数验证
(gdb) call printf("debug: x=%d, y=%d\n", x, y)

修改流程命令对比:

命令 效果 风险
set var=val 修改变量值 低,仅影响数据
return <val> 立即返回 中,跳过清理代码
jump <line> 跳转到指定行 高,可能跳过初始化
call <func> 调用函数 中,有副作用

5.13.7 反向调试(record/reverse-step)

反向调试允许程序"倒着执行",在发现 bug 后回溯到问题产生的源头。

bash 复制代码
# 开始记录程序执行
(gdb) record

# 正常运行到发现问题
(gdb) c
# ... 发现变量值不对 ...

# 反向单步(回退到上一条语句)
(gdb) reverse-step

# 反向单步(不进入函数)
(gdb) reverse-next

# 反向继续(回退到上一个断点)
(gdb) reverse-continue

# 反向执行到函数入口
(gdb) reverse-finish

# 停止记录
(gdb) record stop

反向调试命令对比:

正向命令 反向命令 说明
step reverse-step (rs) 反向进入函数
next reverse-next (rn) 反向不进入函数
continue reverse-continue (rc) 反向到断点
finish reverse-finish 反向到函数入口
stepi reverse-stepi 反向指令级

注意事项:

注意点 说明
性能开销 记录模式会显著降低执行速度
记录长度 默认记录 200000 条指令,可通过 set record insn-number-max 调整
不支持的操作 设备 I/O 等不可逆操作无法回退
适用场景 定位"变量何时被错误修改"类问题

5.14 GDB调试技巧与最佳实践

本节总结 GDB 使用中的高级技巧和最佳实践,包括配置文件、命令别名、优化代码调试注意事项和常见问题的解决方案。

5.14.1 .gdbinit 配置技巧(自动化调试环境)

.gdbinit 文件在 GDB 启动时自动执行,可以预设常用配置,提升调试效率。

加载顺序与作用范围:

位置 加载顺序 作用范围 安全要求
/etc/gdb/gdbinit 最先 系统全局 需编译时启用
~/.config/gdb/gdbinit~/.gdbinit 其次 用户全局 无限制
./.gdbinit 再次 项目级 需要 set auto-load local-gdbinit
-x 指定的文件 最后 命令行指定 无限制

安全注意事项:

GDB 默认不加载当前目录的 .gdbinit(出于安全考虑),需要设置:

bash 复制代码
# 在 ~/.gdbinit 中添加
set auto-load local-gdbinit

这是因为恶意的 .gdbinit 文件可能在用户不知情的情况下执行任意命令。如果经常在不同项目间切换,建议只信任自己创建的项目级 .gdbinit

常用配置示例(~/.gdbinit):

bash 复制代码
# ===== 打印格式设置 =====
set print pretty on              # 结构体多行显示
set print array on               # 数组多行显示
set print array-indexes on       # 显示数组下标
set print elements 200           # 最多显示 200 个元素
set print null-stop on           # 字符串遇 NULL 停止

# ===== 历史记录设置 =====
set history filename ~/.gdb_history
set history save on
set history size 10000

# ===== 自定义命令:显示当前 PC 开始的 8 条指令 =====
define li
    x /8i $pc
end
document li
    显示当前地址开始的 8 条指令
end

# ===== 自定义命令:显示当前栈帧的详细信息 =====
define fi
    info frame
    info args
    info locals
end

# ===== 自定义命令:显示寄存器 =====
define regs
    info registers
end

# ===== 自定义命令:所有线程堆栈 =====
define allbt
    thread apply all bt
end

项目级 .gdbinit 示例(嵌入式交叉调试):

bash 复制代码
# 项目级 .gdbinit(放在项目根目录)
# 自动连接目标板
target remote 192.168.110.125:2345

# 设置符号文件路径
symbol-file ./build/out.elf

# 设置常用断点
b main
b error_handler

配置分类建议:

配置类型 放置位置 示例
通用格式设置 ~/.gdbinit print pretty、history
通用自定义命令 ~/.gdbinit li、fi、regs
项目特定配置 ./.gdbinit target remote、项目断点
临时调试脚本 -x file.gdb 一次性调试任务

5.14.2 GDB命令别名与缩写

完整命令 缩写 说明
break b 设置断点
run r 运行
continue c 继续
next n 单步(不进入函数)
step s 单步(进入函数)
finish fin 执行到函数返回
until u 执行到指定位置
print p 打印
display disp 自动显示
backtrace bt 查看堆栈
frame f 切换栈帧
info i 查看信息
delete d 删除
disable dis 禁用
enable en 启用
quit q 退出

自定义别名(GDB 9+):

bash 复制代码
# 使用 alias 命令创建别名
(gdb) alias -a bb = break
(gdb) alias -a ss = set scheduler-locking

# 在 .gdbinit 中设置
alias -a bb = break
alias -a ss = set scheduler-locking

5.14.3 调试优化后代码的注意事项

使用 -O2 或更高优化级别编译的代码,调试时可能遇到以下问题:

问题 原因 解决方法
变量显示 <optimized out> 变量被优化到寄存器或被消除 使用 -O0-Og 重新编译
代码行号跳跃 代码被重排或内联 使用 disas 查看实际执行顺序
断点无法设置 代码被优化掉 使用地址断点 b *0x...
函数不可见 函数被内联 使用 -fno-inline 编译
参数值不正确 参数通过寄存器传递被复用 使用 disas 确认实际传参

推荐调试编译选项:

bash 复制代码
# 最佳调试体验
gcc -O0 -g -ggdb -o program program.c

# 需要一定性能时的调试
gcc -Og -g -ggdb -o program program.c

# 必须使用高优化级别时(如复现特定 bug)
gcc -O2 -g -ggdb -fno-omit-frame-pointer -o program program.c

优化级别与调试体验对比:

优化级别 调试体验 性能 适用场景
-O0 最佳(所有变量可见) 最慢 日常开发调试
-Og 良好(大部分变量可见) 中等 需要一定性能的调试
-O1 一般 较快 平衡选择
-O2 较差(变量可能消失) 复现优化相关 bug
-O3 最差 最快 仅在必要时使用

5.14.4 常见调试问题与解决方案

问题 原因 解决方法
(no debugging symbols found) 编译时未加 -g 重新编译并添加 -g -ggdb
No source file named xxx.c 源文件路径不匹配 使用 directory-d 指定源文件路径
断点显示 PENDING 共享库尚未加载 使用 set breakpoint pending on
Cannot access memory at address 指针无效或程序已退出 检查指针值,确认程序仍在运行
观察点不触发 硬件观察点数量限制 减少观察点数量,或使用软件观察点
attach: ptrace: Operation not permitted 权限不足 使用 sudo 或修改 ptrace_scope
warning: Could not load shared library symbols 找不到动态库 set solib-search-path <path>
Dwarf Error: wrong version in compilation unit header 调试信息版本不匹配 更新 GDB 或重新编译

修改 ptrace 权限(Ubuntu):

bash 复制代码
# 临时修改
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

# 永久修改
$ sudo vim /etc/sysctl.d/10-ptrace.conf
# 将 kernel.yama.ptrace_scope = 1 改为 0

5.14.5 GDB与其他工具配合

场景 工具组合 说明
崩溃分析 dmesg + addr2line + gdb 先定位地址,再深入分析
内存问题 valgrind / ASan + gdb 先检测问题,再用 GDB 定位
性能问题 perf + gdb 先用 perf 找热点,再用 GDB 分析逻辑
系统调用 strace + gdb 先用 strace 确认系统调用行为
多线程 pstack + gdb 先用 pstack 快速查看栈,再用 GDB 深入
内核交互 ftrace + gdb 内核行为用 ftrace,用户态用 GDB

工具配合流程图:
#mermaid-svg-VlmhmfwhUmKuwtPO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VlmhmfwhUmKuwtPO .error-icon{fill:#552222;}#mermaid-svg-VlmhmfwhUmKuwtPO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VlmhmfwhUmKuwtPO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VlmhmfwhUmKuwtPO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VlmhmfwhUmKuwtPO .marker.cross{stroke:#333333;}#mermaid-svg-VlmhmfwhUmKuwtPO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VlmhmfwhUmKuwtPO p{margin:0;}#mermaid-svg-VlmhmfwhUmKuwtPO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO .cluster-label text{fill:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO .cluster-label span{color:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO .cluster-label span p{background-color:transparent;}#mermaid-svg-VlmhmfwhUmKuwtPO .label text,#mermaid-svg-VlmhmfwhUmKuwtPO span{fill:#333;color:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO .node rect,#mermaid-svg-VlmhmfwhUmKuwtPO .node circle,#mermaid-svg-VlmhmfwhUmKuwtPO .node ellipse,#mermaid-svg-VlmhmfwhUmKuwtPO .node polygon,#mermaid-svg-VlmhmfwhUmKuwtPO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VlmhmfwhUmKuwtPO .rough-node .label text,#mermaid-svg-VlmhmfwhUmKuwtPO .node .label text,#mermaid-svg-VlmhmfwhUmKuwtPO .image-shape .label,#mermaid-svg-VlmhmfwhUmKuwtPO .icon-shape .label{text-anchor:middle;}#mermaid-svg-VlmhmfwhUmKuwtPO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VlmhmfwhUmKuwtPO .rough-node .label,#mermaid-svg-VlmhmfwhUmKuwtPO .node .label,#mermaid-svg-VlmhmfwhUmKuwtPO .image-shape .label,#mermaid-svg-VlmhmfwhUmKuwtPO .icon-shape .label{text-align:center;}#mermaid-svg-VlmhmfwhUmKuwtPO .node.clickable{cursor:pointer;}#mermaid-svg-VlmhmfwhUmKuwtPO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VlmhmfwhUmKuwtPO .arrowheadPath{fill:#333333;}#mermaid-svg-VlmhmfwhUmKuwtPO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VlmhmfwhUmKuwtPO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VlmhmfwhUmKuwtPO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VlmhmfwhUmKuwtPO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VlmhmfwhUmKuwtPO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VlmhmfwhUmKuwtPO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VlmhmfwhUmKuwtPO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VlmhmfwhUmKuwtPO .cluster text{fill:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO .cluster span{color:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VlmhmfwhUmKuwtPO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VlmhmfwhUmKuwtPO rect.text{fill:none;stroke-width:0;}#mermaid-svg-VlmhmfwhUmKuwtPO .icon-shape,#mermaid-svg-VlmhmfwhUmKuwtPO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VlmhmfwhUmKuwtPO .icon-shape p,#mermaid-svg-VlmhmfwhUmKuwtPO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VlmhmfwhUmKuwtPO .icon-shape .label rect,#mermaid-svg-VlmhmfwhUmKuwtPO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VlmhmfwhUmKuwtPO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VlmhmfwhUmKuwtPO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VlmhmfwhUmKuwtPO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 崩溃
内存
性能
系统调用
发现问题
问题类型?
dmesg 获取地址
addr2line 定位
GDB 深入分析
Valgrind/ASan 检测
perf record 采样
perf report 找热点
strace 跟踪

5.14.6 GDB实用设置速查

设置命令 说明 推荐值
set print pretty on 结构体美化显示 on
set print array on 数组美化显示 on
set print elements 0 不限制数组显示长度 0 或 200
set history save on 保存命令历史 on
set history size 10000 历史记录条数 10000
set pagination off 关闭分页(脚本模式) 脚本时 off
set confirm off 关闭确认提示 可选
set breakpoint pending on 允许 pending 断点 on
set follow-fork-mode child 跟踪子进程 按需
set scheduler-locking step 单步时锁定线程 多线程调试时

5.15 本章小结

GDB 是 Linux 下最核心的调试工具,掌握其核心功能对嵌入式开发和系统编程至关重要。本章覆盖了 GDB 的完整知识体系:
#mermaid-svg-uCLa1fopgyce9Xiq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uCLa1fopgyce9Xiq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uCLa1fopgyce9Xiq .error-icon{fill:#552222;}#mermaid-svg-uCLa1fopgyce9Xiq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uCLa1fopgyce9Xiq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uCLa1fopgyce9Xiq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uCLa1fopgyce9Xiq .marker.cross{stroke:#333333;}#mermaid-svg-uCLa1fopgyce9Xiq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uCLa1fopgyce9Xiq p{margin:0;}#mermaid-svg-uCLa1fopgyce9Xiq .edge{stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .section--1 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section--1 path,#mermaid-svg-uCLa1fopgyce9Xiq .section--1 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section--1 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section--1 text{fill:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth--1{stroke-width:17;}#mermaid-svg-uCLa1fopgyce9Xiq .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-0 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-0 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-0 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-0 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-0 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-0{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-0{stroke-width:14;}#mermaid-svg-uCLa1fopgyce9Xiq .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-1 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-1 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-1 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-1 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-1 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-1{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-1{stroke-width:11;}#mermaid-svg-uCLa1fopgyce9Xiq .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-2 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-2 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-2 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-2 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-2 text{fill:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-2{stroke-width:8;}#mermaid-svg-uCLa1fopgyce9Xiq .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-3 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-3 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-3 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-3 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-3 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-3{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-3{stroke-width:5;}#mermaid-svg-uCLa1fopgyce9Xiq .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-4 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-4 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-4 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-4 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-4 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-4{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-4{stroke-width:2;}#mermaid-svg-uCLa1fopgyce9Xiq .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-5 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-5 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-5 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-5 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-5 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-5{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-5{stroke-width:-1;}#mermaid-svg-uCLa1fopgyce9Xiq .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-6 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-6 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-6 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-6 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-6 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-6{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-6{stroke-width:-4;}#mermaid-svg-uCLa1fopgyce9Xiq .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-7 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-7 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-7 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-7 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-7 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-7{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-7{stroke-width:-7;}#mermaid-svg-uCLa1fopgyce9Xiq .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-8 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-8 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-8 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-8 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-8 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-8{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-8{stroke-width:-10;}#mermaid-svg-uCLa1fopgyce9Xiq .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-9 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-9 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-9 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-9 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-9 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-9{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-9{stroke-width:-13;}#mermaid-svg-uCLa1fopgyce9Xiq .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-10 rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-10 path,#mermaid-svg-uCLa1fopgyce9Xiq .section-10 circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-10 polygon,#mermaid-svg-uCLa1fopgyce9Xiq .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-10 text{fill:black;}#mermaid-svg-uCLa1fopgyce9Xiq .node-icon-10{font-size:40px;color:black;}#mermaid-svg-uCLa1fopgyce9Xiq .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .edge-depth-10{stroke-width:-16;}#mermaid-svg-uCLa1fopgyce9Xiq .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled,#mermaid-svg-uCLa1fopgyce9Xiq .disabled circle,#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:lightgray;}#mermaid-svg-uCLa1fopgyce9Xiq .disabled text{fill:#efefef;}#mermaid-svg-uCLa1fopgyce9Xiq .section-root rect,#mermaid-svg-uCLa1fopgyce9Xiq .section-root path,#mermaid-svg-uCLa1fopgyce9Xiq .section-root circle,#mermaid-svg-uCLa1fopgyce9Xiq .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-uCLa1fopgyce9Xiq .section-root text{fill:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .section-root span{color:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .section-2 span{color:#ffffff;}#mermaid-svg-uCLa1fopgyce9Xiq .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-uCLa1fopgyce9Xiq .edge{fill:none;}#mermaid-svg-uCLa1fopgyce9Xiq .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-uCLa1fopgyce9Xiq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GDB调试
启动与连接
本地调试
远程交叉调试
Coredump调试
附加运行进程
执行控制
运行/停止
单步执行
执行到指定位置
函数调用
断点与观察点
条件断点
观察点
捕捉点
断点管理
数据操作
内存查看x
变量打印p
自动显示display
变量修改set
堆栈分析
backtrace
栈帧切换
寄存器查看
高级调试
多线程调试
多进程调试
信号处理
反向调试
自定义命令
Python脚本

核心命令记忆口诀:

类别 核心命令
运行 r(run)、c(continue)、start
单步 n(next)、s(step)、fin(finish)、u(until)
断点 b(break)、watchtb(tbreak)
查看 p(print)、xbt(backtrace)、disp(display)
堆栈 btf(frame)、updown
线程 info threadsthread Nthread apply all bt
进程 attachdetachset follow-fork-mode
管理 d(delete)、dis(disable)、en(enable)、ignore
反向 recordrs(reverse-step)、rn(reverse-next)、rc(reverse-continue)

GDB 调试场景速查总表:

调试场景 核心命令组合 说明
程序崩溃 runbtpx 运行→堆栈→变量→内存
逻辑错误 bn/spdisplay 断点→单步→打印→监控
内存越界 watchcbt 观察点→继续→堆栈
死锁 Ctrl+Cthread apply all bt 中断→所有线程堆栈
性能相关 recordrs/rn 记录→反向调试
远程调试 target remotebc 连接→断点→继续
事后分析 gdb program corebt 加载→堆栈
相关推荐
艾伦_耶格宇1 小时前
【ELK】-5 kibana和filebeat
linux·运维·ubuntu·elk
DevHub1 小时前
电视盒子刷 Armbian 教程:30 元旧盒子变 NAS 跑 Docker,200+ 机型可刷
linux·嵌入式硬件·docker·容器·开源·电视盒子
Doraemomo4 小时前
Linux编程-线程
linux·运维·服务器
Linux-lucky10 小时前
21-Linux学习之旅之HTTPS和安全加固
linux·运维·学习·ubuntu·https
清水白石00810 小时前
Python 死锁排查全攻略:从线程卡死到锁依赖定位与工程化修复
linux·网络·python
ao-weilai12 小时前
Linux基础:Ext系列文件系统
linux·运维·服务器
qq_3494479512 小时前
Linux系统,安装git,从使用git下载仓库(GitHub, Gitee, GitLab 等),并且使用ssh密钥,可以直接执行git pull
linux·git·ssh
mCell15 小时前
GitHub Actions 玩法大赏:一台远程主机的七种活法
linux·github·agent