跳转至

GDB调试器

概述

GDB(GNU Debugger)是GNU项目的调试器,支持多种编程语言和处理器架构。

基本使用

启动GDB

Bash
# 编译时加入调试信息
gcc -g program.c -o program

# 启动GDB
gdb program
gdb --args program arg1 arg2

# 附加到运行中的进程
gdb -p <pid>
gdb program <pid>

运行程序

Bash
1
2
3
4
5
6
(gdb) run                 # 运行程序
(gdb) run arg1 arg2       # 带参数运行
(gdb) start               # 运行并停在main
(gdb) starti              # 运行并停在第一条指令
(gdb) continue            # 继续运行
(gdb) continue 5          # 继续5次

断点操作

设置断点

Bash
(gdb) break main          # 函数断点
(gdb) break file.c:100    # 行号断点
(gdb) break file.c:func   # 文件中函数断点
(gdb) break *0x400000     # 地址断点
(gdb) break func if x>10  # 条件断点
(gdb) tbreak main         # 临时断点(只触发一次)

# 缩写
(gdb) b main
(gdb) b file.c:100

管理断点

Bash
(gdb) info breakpoints    # 查看断点
(gdb) info break 1        # 查看特定断点

(gdb) delete 1            # 删除断点1
(gdb) delete              # 删除所有断点

(gdb) disable 1           # 禁用断点1
(gdb) enable 1            # 启用断点1
(gdb) enable once 1       # 启用一次

(gdb) clear main          # 清除函数断点
(gdb) clear file.c:100    # 清除行断点

(gdb) ignore 1 10         # 忽略断点1的接下来10次触发

观察点

Bash
1
2
3
4
5
6
(gdb) watch variable      # 监视变量变化
(gdb) watch *0x400000     # 监视地址变化
(gdb) rwatch variable     # 监视读取
(gdb) awatch variable     # 监视读写

(gdb) info watchpoints    # 查看观察点

单步执行

Bash
(gdb) step                # 单步进入(进入函数)
(gdb) step 5              # 执行5步

(gdb) next                # 单步跳过(不进入函数)
(gdb) next 5              # 执行5步

(gdb) finish              # 执行到函数返回
(gdb) until               # 执行到循环结束
(gdb) until 100           # 执行到指定行

(gdb) stepi               # 汇编级单步进入
(gdb) nexti               # 汇编级单步跳过

查看信息

变量和表达式

Bash
(gdb) print variable      # 打印变量
(gdb) print/x variable    # 十六进制格式
(gdb) print/d variable    # 十进制格式
(gdb) print/t variable    # 二进制格式
(gdb) print/c variable    # 字符格式

(gdb) print *ptr          # 打印指针指向的值
(gdb) print arr[0]@10     # 打印数组前10个元素
(gdb) print sizeof(var)   # 打印变量大小
(gdb) print my_func()     # 调用函数

(gdb) ptype variable      # 查看变量类型
(gdb) whatis variable     # 查看变量类型简短

内存查看

Bash
1
2
3
4
5
6
7
8
(gdb) x/10x 0x400000      # 查看10个十六进制字
(gdb) x/10i 0x400000      # 查看10条指令
(gdb) x/10s 0x400000      # 查看10个字符串
(gdb) x/10c 0x400000      # 查看10个字符

# 格式: x/NFU address
# N: 数量, F: 格式, U: 单位
# 单位: b(字节), h(半字), w(字), g(双字)

寄存器

Bash
1
2
3
4
(gdb) info registers      # 查看所有寄存器
(gdb) info reg rax        # 查看特定寄存器
(gdb) print $rax          # 打印寄存器值
(gdb) set $rax = 100      # 设置寄存器值

调用栈

Bash
(gdb) backtrace           # 查看调用栈
(gdb) bt                  # 缩写
(gdb) bt 5                # 查看前5层
(gdb) bt full             # 包含局部变量

(gdb) frame 2             # 切换到第2层
(gdb) up                  # 上移一层
(gdb) down                # 下移一层

(gdb) info frame          # 查看当前帧信息
(gdb) info args           # 查看函数参数
(gdb) info locals         # 查看局部变量

修改变量

Bash
1
2
3
4
(gdb) set variable = 100          # 设置变量
(gdb) set var = 100               # 缩写
(gdb) set *ptr = 100              # 设置指针指向的值
(gdb) set {int}0x400000 = 100     # 设置内存值

源码查看

Bash
1
2
3
4
5
(gdb) list                  # 查看源码
(gdb) list main             # 查看函数源码
(gdb) list file.c:100       # 查看文件行
(gdb) list 100,120          # 查看行范围
(gdb) set listsize 20       # 设置显示行数

多线程调试

Bash
1
2
3
4
5
(gdb) info threads          # 查看所有线程
(gdb) thread 2              # 切换到线程2
(gdb) thread apply all bt   # 所有线程调用栈
(gdb) set scheduler-locking on    # 锁定调度器
(gdb) set scheduler-locking off   # 解锁调度器

多进程调试

Bash
1
2
3
(gdb) set follow-fork-mode child    # 跟踪子进程
(gdb) set follow-fork-mode parent   # 跟踪父进程
(gdb) set detach-on-fork off        # 两个进程都跟踪

远程调试

目标机

Bash
1
2
3
# 启动gdbserver
gdbserver :1234 program
gdbserver :1234 --attach <pid>

开发机

Bash
1
2
3
gdb program
(gdb) target remote 192.168.1.100:1234
(gdb) target remote localhost:1234

核心转储

Bash
# 启用核心转储
ulimit -c unlimited

# 分析核心转储
gdb program core
gdb program core.12345

# 在GDB中
(gdb) bt                    # 查看崩溃时调用栈
(gdb) info registers        # 查看寄存器状态

GDB脚本

.gdbinit文件

Bash
# ~/.gdbinit
set auto-load safe-path /
set history save on
set print pretty on

# 自定义命令
define plist
    set $node = $arg0
    while $node
        print *$node
        set $node = $node->next
    end
end

执行脚本

Bash
1
2
3
4
(gdb) source script.gdb    # 加载脚本
(gdb) define cmd           # 定义命令
    > print $arg0
    > end

TUI模式

Bash
# 启动TUI模式
gdb -tui program

# 或在GDB中
(gdb) tui enable
(gdb) tui disable

# 快捷键
Ctrl+x a    # 切换TUI模式
Ctrl+x 2    # 双窗口
Ctrl+x s    # 单窗口

常用技巧

显示变量变化

Bash
1
2
3
4
(gdb) display variable     # 每次停止时显示
(gdb) display/x variable   # 十六进制格式
(gdb) info display         # 查看display列表
(gdb) undisplay 1          # 删除display

捕获信号

Bash
1
2
3
4
5
(gdb) info signals         # 查看信号处理
(gdb) handle SIGINT stop   # 停止程序
(gdb) handle SIGINT nostop # 不停止
(gdb) handle SIGINT print  # 打印信息
(gdb) handle SIGINT noprint # 不打印

参考资料