惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
T
Tenable Blog
T
Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
D
Darknet – Hacking Tools, Hacker News & Cyber Security
K
Kaspersky official blog
Security Latest
Security Latest
P
Privacy & Cybersecurity Law Blog
Google Online Security Blog
Google Online Security Blog
SecWiki News
SecWiki News
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
Webroot Blog
Webroot Blog
Spread Privacy
Spread Privacy
O
OpenAI News
The Last Watchdog
The Last Watchdog
P
Proofpoint News Feed
C
Check Point Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
人人都是产品经理
人人都是产品经理
S
Security @ Cisco Blogs
Scott Helme
Scott Helme
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
月光博客
月光博客
S
Securelist
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
T
Troy Hunt's Blog
W
WeLiveSecurity
GbyAI
GbyAI
N
News | PayPal Newsroom
Y
Y Combinator Blog
C
Cisco Blogs
H
Help Net Security
The GitHub Blog
The GitHub Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 【当耐特】
Jina AI
Jina AI
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
云风的 BLOG
云风的 BLOG
小众软件
小众软件
N
News and Events Feed by Topic

博客园_首页

Plist 二进制格式 Milvus 和 PGVector,哪个更好? OpenClaw 已过时?在 VS Code 中运行 Hermes Agent! 第30篇文章:一个大三计科生的自白 Manim如何在数学公式中完美显示中文? Docker 部署 RocketMQ 5 并发编程核心概念辨析 C#事务处理最佳实践:别再让“主表存了、明细丢了”的破事发生 CLI 是什么?为什么大厂突然集体卷命令行? 【从0到1构建一个ClaudeAgent】协作-自主Agent UIImageView 设置图片不生效的原因排查 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法 AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布 Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量 在后台服务中使用 Scoped 服务,为什么总是报错? H200 安装驱动并使用sglang启动模型 wireshark 抓包Trap上报告警内容 我用 AI 辅助开发了一系列小工具(2):图片压缩工具 [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型 Oracle数据库SCN推进技术详解与实践指南 玩转控件:封装个带图片的Label控件 Claude Code 4.7 真正该升级的不是模型,而是你的工作流 前端小白一句话,AI 帮我做了个颜值拉满的桌面媒体播放器。当代码不再是门槛,一句话编程就是现实。 5. WorkBuddy: 小龙虾的灵魂三件套,让你的小龙虾不只是工具 SQLite 分片方案实战:三种分片策略的深度对比 告别简陋 UI!一款基于 Fluent Design 和基于 WinUI 的开源免费、现代化的 Avalonia UI 控件库 关于二进制排列组合枚举的总结 AI开发-python-LangGraph框架(3-27-LangGraph从零实现大模型智能决策工作流) ElasticSearch主分片和副本分片概念详解 【002】HTTPS 粗解:证书、TLS 握手与对后端配置的影响 Hermes Agent 一周暴涨五万 Star,但我劝你别急着追 明明连接的是Redis的DB0,为什么能查到DB3的数据? 【从0到1构建一个ClaudeAgent】协作-Agent团队 熟悉电子元器件之后,电子小白下一步该怎么走? MAF快速入门(23)通过C#类定义Skills .NET 高级开发 | 手写一个对象映射框架 FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 mysqldump 参数拾遗:在遗忘与铭记之间 C# .NET 周刊|2026年3月5期 Claude code入门 - 陈彦斌 一文学习入门 ThingsBoard 开源物联网平台 GitHub 热门项目 | 2026年04月16日 如何为GIT设置全局勾子,为每次提交追加信息 Number.isFinite和isFinite与isNaN()和Number.isNaN的区别 PortSwigger SQL注入LAB2 推荐一个测试人必备的Skills,从功能到性能全搞定(附详细实操和安装下载方式) 筑基期:掌握Odoo基础核心知识点02(Odoo XML 开发方式详解) GLM模型这么火,咱们用vllm也咧一个呗! 深入理解 AbortController:从底层原理到跨语言设计哲学 字符串学习笔记 多租户系统框架的基础模块设计和分析设计 Apache SeaTunnel Zeta 为什么能做到“又快又稳”? AI开发-python-LangGraph框架(3-26-LangGraph基本概念及第一个简单样例) Vue 3 组件通信,别只会用 Props 和 Emits 了,这几个狠活儿你得看看 ElasticSearch7.X版本配置密码 用Manim实现动态交点计算--从一个动点问题说起 团结引擎+Addressable+Instant Game打包抖音小游戏 function call 实战:让 LLM 自动判断 pod 异常、调用日志工具并完成故障分析 bubseek —— 让 Agent 的足迹,变成团队的洞察 通过 C# 读取并导出 PDF 书签 如何用 GitHub Actions 实现 Steam 自动化发布 【从0到1构建一个ClaudeAgent】并发-后台任务 .NET 高级开发 | 定制 ASP.NET Core 框架 电子小白:什么是运算放大器(运放) zero2Agent:面向大厂面试的 Agent 工程教程,从概念到生产的完整学习路线 堆上的ORW HC32F460 USB CDC通信异常:非对齐访问异常排查 20260413-Hyperbridge 攻击事件:发生在默克尔山上的验证绕过 那些喊着AI 要淘汰你的人,正在靠你的焦虑赚大钱! 深度学习进阶(八)Swin Transformer 最小二乘问题详解19:带先验约束的增量式SFM优化与实现 SnapTranslate 3.0 正式发布:全局划词翻译 + 完整英语学习闭环,一站式搞定查词、记词、复习 工作的意义、工作的困难认知再思考 .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 开了 TUN 模式还是直连?90% 的人都踩过这个坑 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术
GDB 调试命令完整指南(ARM Cortex-M 嵌入式版)
alanala · 2026-05-19 · via 博客园_首页

GDB 调试命令完整指南(ARM Cortex-M 嵌入式版)

目标平台:ARM Cortex-M4 (STM32F411),工具链:arm-none-eabi-gdb


目录

  1. 命令语法约定
  2. x — 内存查看
  3. print — 变量/表达式打印
  4. info — 信息查询
  5. break — 断点
  6. 监视点
  7. 执行控制
  8. monitor — 调试器后端命令
  9. set — 修改状态
  10. disassemble — 反汇编
  11. 栈帧与回溯
  12. display — 自动显示
  13. TUI — 文本界面
  14. 实用组合技

1. 命令语法约定

GDB 命令格式:命令 [子命令] [参数...]

符号 含义
[ ] 可选参数
< > 必填参数
| 二选一
* 地址

缩写规则:GDB 命令可缩写到唯一不冲突的最短形式。例如 continuecbreakbexaminexinfoiprintpstepsnextn


2. x — 内存查看 (eXamine)

2.1 命令结构

x  /  数量  格式  单位  地址
↑  ↑   ↑    ↑    ↑    ↑
|  |   |    |    |    └── 起始地址(可以是 $sp、$pc、0x20000000、&var)
|  |   |    |    └────── 单位 (Unit):b=字节(8bit) h=半字(16bit) w=字(32bit) g=巨字(64bit)
|  |   |    └─────────── 格式 (Format):x=十六进制 d=十进制有符号 u=十进制无符号 o=八进制
|  |   |                           t=二进制 f=浮点数 a=地址 s=字符串 i=指令(反汇编) c=字符
|  |   └──────────────── 数量:要显示多少个单元
|  └──────────────────── 格式分隔符(固定斜杠)
└─────────────────────── 命令名:eXamine 的缩写

2.2 格式 (Format) 详解

格式符 英文全称 显示方式 示例输出
x hexadecimal 十六进制 0x2001ffac
d decimal (signed) 十进制有符号 -42
u unsigned decimal 十进制无符号 4294967254
o octal 八进制 0377
t binary 二进制 10101010
f float 浮点数 3.14159
a address 地址指针 0x2001ffac <var_name>
c character 字符 65 'A'
s string \0 结尾的字符串 "Hello World"
i instruction 反汇编为汇编指令 ldr r3, [r2, #0]

2.3 单位 (Unit) 详解

单位符 英文全称 大小
b Byte 1 字节 (8 bit)
h Half-word 2 字节 (16 bit)
w Word 4 字节 (32 bit)
g Giant word 8 字节 (64 bit)

2.4 示例拆解

x/8xw $sp
│││││ └─ $sp          = 从 Stack Pointer 指向的地址开始
││││└─── w            = Word (4字节) 为单位显示
│││└──── x            = heXadecimal (十六进制) 格式
││└───── 8            = 显示 8 个单元 (即 8 个 word = 32 字节)
│└────── /            = 格式分隔符
└─────── x            = eXamine 命令

输出示例:

(gdb) x/8xw $sp
0x2001ffac: 0x00000000  0xe000e100  0x0000007b  0x00000003
0x2001ffbc: 0x00000000  0x0800028f  0x08000272  0x01000000

对应 Cortex-M 异常栈帧:

地址         值          寄存器
0x2001ffac   0x00000000 → R0
0x2001ffb0   0xe000e100 → R1
0x2001ffb4   0x0000007b → R2
0x2001ffb8   0x00000003 → R3
0x2001ffbc   0x00000000 → R12
0x2001ffc0   0x0800028f → LR (stacked)
0x2001ffc4   0x08000272 → PC (stacked) ← 真正崩溃点
0x2001ffc8   0x01000000 → xPSR

2.5 更多示例

x/4xb  $sp                        # 4 个 Byte,十六进制
x/10ch 0x20000000                 # 10 个 Char (半字单位显示字符)
x/32xw 0x20000000                 # 32 个 Word,十六进制
x/20i  $pc                        # 从 PC 开始反汇编 20 条指令
x/s    0x20000100                 # 打印 null 结尾字符串
x/1s   &msg                       # 同上,用变量地址

3. print — 变量/表达式打印 (Print)

3.1 命令结构

print  [/格式]  表达式
p      [/f]     <expr>

3.2 格式后缀(跟在 / 后)

缩写 英文 含义
x hex 十六进制
d decimal 十进制有符号
u unsigned 十进制无符号
o octal 八进制
t binary 二进制
f float 浮点数
a address 地址形式
c char 字符
s string 字符串

3.3 示例拆解

print/x $lr
│     │  └─ $lr         = Link Register(R14)
│     └──── x           = heXadecimal(十六进制输出)
└────────── print       = 打印命令
print/x *(uint32_t*)0x40021000
│     │  │ │        └─ 外设寄存器地址(RCC_CR)
│     │  │ └─ uint32_t*  = 强制转换为 32 位无符号整型指针
│     │  └─ (uint32_t*)  = C 风格强制类型转换
│     │  └─ *(...)       = 解引用:读该地址的值
│     └── x              = 以十六进制输出
└──────── print          = 打印

3.4 常用表达式

print  var                       # 打印变量值(默认十进制)
print/x var                      # 变量值十六进制
print  *ptr                      # 解引用指针
print  array[0]@10               # 打印数组前 10 个元素
print  sizeof(struct_type)       # 结构体大小
print  &var                      # 变量地址
print  func_name                 # 函数地址
print/x $pc                      # 程序计数器
print/x $sp                      # 栈指针
print/x $lr                      # 链接寄存器
print/x $msp                     # 主栈指针
print/x $psp                     # 进程栈指针
print/x $xpsr                    # 程序状态寄存器
print/x $cfsr                    # 可配置故障状态寄存器
print/x $hfsr                    # HardFault 状态寄存器
print/x $bfar                    # 总线故障地址寄存器
print/x $mmfar                   # 内存管理故障地址寄存器

4. info — 信息查询 (Info)

4.1 info registers — 寄存器

info registers [寄存器组名]
info  reg
i      r
info registers                   # 所有核心寄存器 (R0-R15, CPSR)
info all-registers               # 含 FPU 的全部寄存器
info registers r0 r1 r2          # 仅显示指定寄存器

4.2 info breakpoints — 断点列表

info breakpoints
info b
i     b

输出解读:

Num  Type           Disp Enb Address    What
1    breakpoint     keep y   0x08000272 in funcB at main.c:60
│    │              │    │   │          │        │
│    │              │    │   │          │        └─ 源文件:行号
│    │              │    │   │          └── 函数名
│    │              │    │   └── 地址
│    │              │    └── enabled(y)/disabled(n)
│    │              └── disposition: keep=永久 del=命中后删除
│    └── type: breakpoint / hw breakpoint / watchpoint
└── Num: 断点编号(delete/enable/disable 用此编号操作)

4.3 info line — 地址查询

info line *地址
info line 函数名
info line 文件名:行号
info line *0x08000272            # 返回:Line 62 of "main.c" starts at address 0x08000272
info line main                   # 返回 main 函数的地址范围
info line main.c:42              # 返回第 42 行的地址

注意info line 只对 Flash 代码地址(0x08xxxxxx)有效,RAM 地址(0x20xxxxxx)无行号信息。

4.4 info locals / info args — 局部变量与参数

info locals                      # 当前栈帧全部局部变量
info args                        # 当前函数全部参数
info variables                   # 所有全局/静态变量(可能很多)
info variables ^app_             # 正则过滤:以 app_ 开头的变量

4.5 info frame — 栈帧详情

info frame
info f

输出解读:

Stack level 0, frame at 0x2001ffac:
 pc = 0x8000430 in HardFault_Handler at stm32f4xx_it.c:90
│                        │                    │
│                        │                    └─ 源文件:行号
│                        └── 函数名
└── PC 当前值
 saved pc = 0x8000272
│         └── 被保存的 PC(即函数返回后应去的地址)

4.6 其他 info 子命令

info threads                     # 所有线程列表
info sharedlibrary               # 已加载的共享库
info symbol 0x08000272           # 地址 → 符号名
info address funcB               # 符号名 → 地址
info source                      # 当前源文件名
info functions                   # 所有函数列表
info functions ^HAL_             # 以 HAL_ 开头的所有函数
info types                       # 所有类型定义
info scope 函数名                # 函数的局部变量范围
info mem                         # 已知内存区域
info files                       # 已加载的文件

5. break — 断点 (BReakpoint)

5.1 命令结构

break [位置] [if 条件]
b

5.2 位置指定方式

break main                       # 函数名
break main.c:42                  # 文件:行号
break *0x08000272                # 绝对地址(带 * 前缀)
break main+64                    # 函数偏移
break +10                        # 当前行 +10
break -5                         # 当前行 -5

5.3 硬件断点

Cortex-M4 仅支持 4~6 个硬件断点(软件断点无限但只能设在 RAM/Flash 可写区)。

hb main                          # Hardware Breakpoint — 硬件断点
hb *0x08000272                   # 硬件地址断点
thbreak main                     # Temporary Hardware Breakpoint — 临时硬件断点,命中 1 次后自动删除
thbreak *0x08000272

5.4 条件断点

break main.c:42 if i == 50       # 当 i==50 时停在 main.c:42
break funcB if ptr == 0          # 指针为空时中断

# 对已有断点添加/修改/删除条件
condition 2 i == 100             # 给 2 号断点加条件
condition 2                      # 删除 2 号断点的条件

5.5 断点管理

info breakpoints                 # 列出全部断点(编号、类型、状态)
enable 2                         # 启用 2 号断点
disable 2                        # 禁用 2 号断点(不删除)
delete 2                         # 删除 2 号断点
delete                           # 删除全部断点
clear main                       # 删除 main 函数上所有断点
clear main.c:42                  # 删除 main.c:42 行的断点
ignore 2 5                       # 忽略 2 号断点 5 次(第 6 次命中才停)

5.6 断点自动命令

commands 2                       # 为 2 号断点绑定自动命令
> silent                         #   命中时不打印通知
> printf "i=%d\n", i             #   打印变量
> continue                       #   自动继续(实现"打点"效果)
> end                            # 结束命令输入

6. 监视点 (Watchpoint)

监视点是硬件断点的一种:当指定地址(变量)的值发生变化时触发。

6.1 命令对比

命令 全称 触发时机
watch var software watchpoint 操作时
rwatch var read watchpoint 操作时
awatch var access watchpoint 读或写

Cortex-M4 通常只支持 1~2 个硬件监视点。

watch global_counter              # 监视 global_counter 被写入
watch *0x20000100                 # 监视该地址被写入
rwatch *0x20000100                # 监视该地址被读取
awatch *0x20000100                # 监视该地址被读或写
info watchpoints                  # 列出监视点
delete 3                          # 删除 3 号监视点

7. 执行控制 (Execution Control)

7.1 命令一览

命令 缩写 英文全称 作用
continue c continue 继续执行直到断点/监视点/手动暂停
step s step into 执行一行源码,进入函数内部
next n step over 执行一行源码,跳过函数调用
stepi si step instruction 执行一条汇编指令,进入
nexti ni next instruction 执行一条汇编指令,跳过
finish fin finish function 执行到当前函数返回
until u until 执行到指定行/地址
run r run 从头启动程序
kill kill 终止被调试程序
detach detach 断开连接但继续运行目标

7.2 step vs next 图解

当前停在第 5 行:   result = add(a, b);
                     ↑           ↑
                  next()      step()
                  → 第 6 行     → 进入 add() 内部第 1 行

7.3 stepi vs nexti 图解

当前停在指令:   bl  0x08000200   (调用子函数)
                  ↑           ↑
                nexti()     stepi()
                → 下条指令    → 进入 0x08000200 处第 1 条指令

7.4 until — 快速跳过循环

until 42                         # 运行到本文件的第 42 行
until *0x08000300                # 运行到指定地址
until                            # 运行到"下一行"(常用于跳出循环)

7.5 手动暂停与恢复

目标正在运行时(GDB 提示 Selected thread is running),需要先暂停:

# 方式 1:键盘中断
Ctrl+C                           # 发送 SIGINT,暂停目标

# 方式 2:monitor 命令(如果支持)
monitor halt                     # 通过调试后端暂停

8. monitor — 调试器后端命令 (Monitor)

monitor 命令将后续内容原样传递给调试后端(J-Link GDB Server / OpenOCD),不经过 GDB 解释。

# 复位
monitor reset                    # 默认复位 (SYSRESETREQ + VECTRESET)
monitor reset 0                  # 同上
monitor reset 1                  # 仅内核复位
monitor reset 2                  # 通过 RESET 引脚复位

# 控制
monitor halt                     # 暂停 CPU
monitor go                       # 继续执行

# 寄存器
monitor regs                     # J-Link 端 dump 全部寄存器

# 内存
monitor memU8  0x20000000 16     # 读 16 个 Unsigned 8bit
monitor memU16 0x20000000 8      # 读 8 个 Unsigned 16bit
monitor memU32 0x20000000 4      # 读 4 个 Unsigned 32bit

# Flash
monitor flash device = STM32F411CE   # 指定 Flash 设备
monitor flash erase                  # 整片擦除

# 设置
monitor speed 4000                # SWD/JTAG 速度 (kHz)
monitor clrbp                     # 清除所有硬件断点
monitor resetbp                   # 在 Reset_Handler 处设断点
monitor sleep 100                 # 等待 100ms(Flash 操作后)

8.2 OpenOCD 场景

monitor reset halt               # 复位并暂停在复位向量
monitor reset init               # 复位 + 执行复位初始化
monitor reset run                # 复位 + 继续运行

monitor mdw 0x20000000 16        # Memory Display Word:读 16 个 word
monitor mdh 0x20000000 16        # Memory Display Halfword
monitor mdb 0x20000000 16        # Memory Display Byte
monitor mww 0x20000000 0xDEAD    # Memory Write Word
monitor mwh 0x20000000 0xBEEF    # Memory Write Halfword
monitor mwb 0x20000000 0xFF      # Memory Write Byte

monitor flash write_image erase firmware.hex   # 烧录 hex
monitor flash write_image erase firmware.bin 0x08000000  # 烧录 bin
monitor verify_image firmware.bin 0x08000000  # 校验
monitor flash erase_sector 0 0 11             # 擦除扇区
monitor flash info 0                           # Flash 信息

monitor targets                    # 列出调试目标
monitor reg                        # OpenOCD 端寄存器 dump

9. set — 修改状态 (SET)

9.1 修改变量/内存

set var flag = 1                  # 修改变量值
set var *ptr = 0x1234             # 修改指针指向的内存
set {int}0x20000000 = 42          # 直接写内存地址(int 类型写入)
set {uint32_t}0x40021014 = 0x01   # 写外设寄存器(RCC_AHB1ENR)

9.2 修改寄存器

set $pc = 0x08000200              # 强制设定 PC(跳转)
set $sp = 0x20010000              # 强制设定 SP(换栈)
set $lr = 0x0800028f              # 强制设定 LR
set $cpsr = 0x01000000            # 强制设定 CPSR

9.3 GDB 行为配置

set confirm off                   # 关闭"确认吗?"提示
set pagination off                # 关闭 "---Type <return>---" 分页暂停
set print pretty on               # 结构体缩进美化显示
set print array on                # 数组展开显示(不用 @ 语法)
set history save on               # 保存命令历史
set logging on                    # 开始记录日志到 gdb.txt
set logging off                   # 停二记录
set logging redirect on           # 日志只写文件,不输出到终端
set disassembly-flavor intel      # 反汇编风格:Intel(不支持 ARM)
set breakpoint pending on         # 允许延迟断点(共享库场景)
set $cortexm3_dwt = 1             # 启用 DWT 相关调试功能

10. disassemble — 反汇编 (Disassemble)

10.1 命令格式

disassemble [选项] [起始地址] [,结束地址]
disas

10.2 示例

disassemble main                 # 反汇编 main 函数
disassemble funcB                # 反汇编 funcB 函数
disassemble 0x08000200, 0x08000300    # 反汇编地址区间
disassemble 0x08000200, +200          # 起始地址 + 字节数
disassemble /m main              # /m:混合源码+反汇编(常用)
disassemble /r main              # /r:显示原始指令编码(十六进制)
disassemble /s 0x08000200        # /s:显示源码行

10.3 x/i — 轻量反汇编

disassemble 更常用,直接看当前指令:

x/10i $pc                        # 从 PC 开始反汇编 10 条
x/20i main                       # 从 main 开始反汇编 20 条

11. 栈帧与回溯 (Backtrace & Frame)

11.1 backtrace — 调用栈回溯

backtrace [选项]
bt        [选项]
bt                               # 打印调用栈
bt full                          # 调用栈 + 每帧局部变量
bt 10                            # 只显示前 10 帧
bt -5                            # 只显示最后 5 帧

输出解读:

#0  HardFault_Handler () at stm32f4xx_it.c:90
#1  <signal handler called>
#2  funcB () at main.c:62
#3  0x0800028f in funcA () at main.c:71
#4  main () at main.c:98
│   │                   │
│   │                   └─ 源码位置
│   └── 当前 PC / 符号名
└── 帧编号(#0 是最内层 = 当前帧)

11.2 frame — 切换/查看栈帧

frame                            # 显示当前栈帧信息
frame 3                          # 切换到 3 号帧
info frame                       # 当前帧详细信息
up                               # 向外层移动 1 帧(frame - 1)
down                             # 向内层移动 1 帧(frame + 1)
up 3                             # 向外层移动 3 帧

11.3 info locals / info args

切换 frame 后查看该帧的上下文:

frame 2                          # 切到 funcB 的栈帧
info locals                      # funcB 的局部变量: ptr, b
info args                        # funcB 的参数(此处无形参)

12. display — 自动显示 (DiSPLAY)

每次程序暂停时,自动显示指定表达式。适合频繁监控的变量/寄存器。

display var                      # 自动显示变量
display/x $pc                    # 自动显示 PC
display/10i $pc                  # 自动显示 PC 附近 10 条汇编
display/x $cfsr                  # 故障场景自动显示 CFSR

info display                     # 列出所有自动显示项
undisplay 1                      # 删除 1 号
undisplay                        # 删除全部
disable display 2                # 临时禁用 2 号
enable display 2                 # 重新启用

13. TUI — 文本界面 (Text User Interface)

13.1 开关与布局

tui enable                       # 进入 TUI(分屏)模式
tui disable                      # 退出 TUI
layout src                       # 源码窗口
layout asm                       # 汇编窗口
layout reg                       # 寄存器窗口
layout split                     # 源码 + 汇编上下分屏
Ctrl+X 1                         # 单窗口模式(快捷键切换)
Ctrl+X 2                         # 双窗口模式
Ctrl+X A                         # 切换 TUI 开关

13.2 窗口操作

focus cmd                        # 焦点移到命令窗口
focus src                        # 焦点移到源码窗口
focus asm                        # 焦点移到汇编窗口
focus reg                        # 焦点移到寄存器窗口
winheight src +5                 # 增大源码窗口 5 行
winheight reg -3                 # 缩小寄存器窗口 3 行
refresh                          # 刷新 TUI 显示

13.3 启动时直接进入 TUI

arm-none-eabi-gdb -tui build/firmware.elf

14. 实用组合技

14.1 HardFault 诊断流程(全命令)

# 第 1 步:暂停目标
Ctrl+C
monitor halt

# 第 2 步:获取栈帧来源
print/x $lr                     # 看 EXC_RETURN
# 0xFFFFFFF9 → MSP, 0xFFFFFFFD → PSP

# 第 3 步:打印当前状态
info registers
# 记下 SP 值

# 第 4 步:dump 栈帧(8-word)
x/8xw $sp
# 或可用 MSP:
x/8xw $msp

# 第 5 步:定位崩溃点和调用来源
info line *<stacked_pc>         # stacked PC = 第 7 个值
info line *<stacked_lr>         # stacked LR = 第 6 个值

# 第 6 步:确定故障类型
print/x $cfsr                   # 细分:MMFSR/BFSR/UFSR
print/x $hfsr                   # 是否 HardFault 升级
print/x $bfar                   # BusFault 的故障地址
print/x $mmfar                  # MemManage 的故障地址

# 第 7 步:查看故障点局部变量
bt full                         # 回溯全部调用栈
frame 2                         # 切到崩溃函数帧
info locals                     # 查看崩溃时的局部变量

14.2 GDB 一键启动脚本

arm-none-eabi-gdb \
  -ex "target remote :2331" \
  -ex "monitor reset" \
  -ex "load" \
  -ex "thbreak main" \
  -ex "continue" \
  build/F411_Cmake_Jlink_HardFault_Test.elf

14.3 GDB 启动配置文件

创建项目根目录的 .gdbinit

# 基础配置
set confirm off
set pagination off
set print pretty on
set history save on

# 自动连接 J-Link
target remote :2331

# 复位 + 烧录 + 停在 main
monitor reset
load
thbreak main
continue

14.4 频繁调试的外设寄存器监控

# 进入 HardFault 后一键运行的诊断脚本
define hf
  printf "=== HardFault Diagnosis ===\n"
  printf "SP    = "; print/x $sp
  printf "MSP   = "; print/x $msp
  printf "PSP   = "; print/x $psp
  printf "LR    = "; print/x $lr
  printf "PC    = "; print/x $pc
  printf "CFSR  = "; print/x $cfsr
  printf "HFSR  = "; print/x $hfsr
  printf "BFAR  = "; print/x $bfar
  printf "MMFAR = "; print/x $mmfar
  printf "\nStack Frame:\n"
  x/8xw $sp
end

# 使用方式
(gdb) hf

创建日期:2026-05-19
适用工具链:arm-none-eabi-gdb (Arm GNU Toolchain)
调试后端:J-Link GDB Server / OpenOCD