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 |
|---|
| (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 |
|---|
| (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 |
|---|
| (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 |
|---|
| (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 |
|---|
| (gdb) set variable = 100 # 设置变量
(gdb) set var = 100 # 缩写
(gdb) set *ptr = 100 # 设置指针指向的值
(gdb) set {int}0x400000 = 100 # 设置内存值
|
源码查看
| Bash |
|---|
| (gdb) list # 查看源码
(gdb) list main # 查看函数源码
(gdb) list file.c:100 # 查看文件行
(gdb) list 100,120 # 查看行范围
(gdb) set listsize 20 # 设置显示行数
|
多线程调试
| Bash |
|---|
| (gdb) info threads # 查看所有线程
(gdb) thread 2 # 切换到线程2
(gdb) thread apply all bt # 所有线程调用栈
(gdb) set scheduler-locking on # 锁定调度器
(gdb) set scheduler-locking off # 解锁调度器
|
多进程调试
| Bash |
|---|
| (gdb) set follow-fork-mode child # 跟踪子进程
(gdb) set follow-fork-mode parent # 跟踪父进程
(gdb) set detach-on-fork off # 两个进程都跟踪
|
远程调试
目标机
| Bash |
|---|
| # 启动gdbserver
gdbserver :1234 program
gdbserver :1234 --attach <pid>
|
开发机
| Bash |
|---|
| 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 |
|---|
| (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 |
|---|
| (gdb) display variable # 每次停止时显示
(gdb) display/x variable # 十六进制格式
(gdb) info display # 查看display列表
(gdb) undisplay 1 # 删除display
|
捕获信号
| Bash |
|---|
| (gdb) info signals # 查看信号处理
(gdb) handle SIGINT stop # 停止程序
(gdb) handle SIGINT nostop # 不停止
(gdb) handle SIGINT print # 打印信息
(gdb) handle SIGINT noprint # 不打印
|
参考资料