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

GDB 调试命令完整指南(ARM Cortex-M 嵌入式版)
1. 命令语法约定GDB 命令格式命令 [子命令] [参数...]符号含义[ ]可选参数 必填参数|二选一*地址缩写规则GDB 命令可缩写到唯一不冲突的最短形式。例如continue→cbreak→bexamine→xinfo→iprint→pstep→snext→n。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) 详解格式符英文全称显示方式示例输出xhexadecimal十六进制0x2001ffacddecimal (signed)十进制有符号-42uunsigned decimal十进制无符号4294967254ooctal八进制0377tbinary二进制10101010ffloat浮点数3.14159aaddress地址指针0x2001ffac var_nameccharacter字符65 Asstring以\0结尾的字符串Hello Worldiinstruction反汇编为汇编指令ldr r3, [r2, #0]2.3 单位 (Unit) 详解单位符英文全称大小bByte1 字节 (8 bit)hHalf-word2 字节 (16 bit)wWord4 字节 (32 bit)gGiant word8 字节 (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 → xPSR2.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] expr3.2 格式后缀跟在/后缩写英文含义xhex十六进制ddecimal十进制有符号uunsigned十进制无符号ooctal八进制tbinary二进制ffloat浮点数aaddress地址形式cchar字符sstring字符串3.3 示例拆解print/x $lr │ │ └─ $lr Link RegisterR14 │ └──── 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 rinfo 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 条件] b5.2 位置指定方式break main # 函数名 break main.c:42 # 文件:行号 break *0x08000272 # 绝对地址带 * 前缀 break main64 # 函数偏移 break 10 # 当前行 10 break -5 # 当前行 -55.3 硬件断点Cortex-M4 仅支持 4~6 个硬件断点软件断点无限但只能设在 RAM/Flash 可写区。hb main # Hardware Breakpoint — 硬件断点 hb *0x08000272 # 硬件地址断点 thbreak main # Temporary Hardware Breakpoint — 临时硬件断点命中 1 次后自动删除 thbreak *0x080002725.4 条件断点break main.c:42 if i 50 # 当 i50 时停在 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 varsoftware watchpoint写操作时rwatch varread watchpoint读操作时awatch varaccess 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 命令一览命令缩写英文全称作用continueccontinue继续执行直到断点/监视点/手动暂停stepsstep into执行一行源码进入函数内部nextnstep over执行一行源码跳过函数调用stepisistep instruction执行一条汇编指令进入nextininext instruction执行一条汇编指令跳过finishfinfinish function执行到当前函数返回untiluuntil执行到指定行/地址runrrun从头启动程序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键盘中断 CtrlC # 发送 SIGINT暂停目标 # 方式 2monitor 命令如果支持 monitor halt # 通过调试后端暂停8. monitor — 调试器后端命令 (Monitor)monitor命令将后续内容原样传递给调试后端J-Link GDB Server / OpenOCD不经过 GDB 解释。8.1 J-Link GDB Server 场景# 复位 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 # 等待 100msFlash 操作后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 端寄存器 dump9. set — 修改状态 (SET)9.1 修改变量/内存set var flag 1 # 修改变量值 set var *ptr 0x1234 # 修改指针指向的内存 set {int}0x20000000 42 # 直接写内存地址int 类型写入 set {uint32_t}0x40021014 0x01 # 写外设寄存器RCC_AHB1ENR9.2 修改寄存器set $pc 0x08000200 # 强制设定 PC跳转 set $sp 0x20010000 # 强制设定 SP换栈 set $lr 0x0800028f # 强制设定 LR set $cpsr 0x01000000 # 强制设定 CPSR9.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 [选项] [起始地址] [,结束地址] disas10.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 # 源码 汇编上下分屏 CtrlX 1 # 单窗口模式快捷键切换 CtrlX 2 # 双窗口模式 CtrlX A # 切换 TUI 开关13.2 窗口操作focus cmd # 焦点移到命令窗口 focus src # 焦点移到源码窗口 focus asm # 焦点移到汇编窗口 focus reg # 焦点移到寄存器窗口 winheight src 5 # 增大源码窗口 5 行 winheight reg -3 # 缩小寄存器窗口 3 行 refresh # 刷新 TUI 显示13.3 启动时直接进入 TUIarm-none-eabi-gdb -tui build/firmware.elf14. 实用组合技14.1 HardFault 诊断流程全命令# 第 1 步暂停目标 CtrlC 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.elf14.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 continue14.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