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


    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
    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   0x00000000R0
    0x2001ffb0   0xe000e100R1
    0x2001ffb4   0x0000007bR2
    0x2001ffb8   0x00000003R3
    0x2001ffbc   0x00000000R12
    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 ---" 分页暂停
    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  
    #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 = 第 7 个值
    info line *         # 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

  • 相关阅读:
    HPA (Horizontal Pod Autoscaler) In K8s
    java基于springboot+jsp高校物资采购管理系统maven项目附源码
    zabbix监控手动部署、邮件告警
    激活函数总结(四十四):激活函数补充(NLSIG、EvoNorms)
    十年后依然火热,大厂内部强推Spring Boot实战类图书
    Hadoop3:MapReduce之简介、WordCount案例源码阅读、简单功能开发
    git提交三板斧(如何把项目代码提交到gitee上——命令行版)
    java集合类常用的方法介绍
    性能测试阶段6之行业流行性能监控工具
    WorkPlus AI智能助理,基于GPT为企业提供专属的私有化部署解决方案
  • 原文地址:https://www.cnblogs.com/Alanla/p/20085900