概述 GDB(GNU Debugger)是 GNU 项目开发的标准调试器,支持 C、C++、Go、Rust 等多种语言。掌握 GDB 是 Linux 下开发的必备技能。
一、GDB 基本使用 1.1 启动 GDB 1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 调试可执行文件
gdb ./program
# 调试带参数的程序
gdb --args ./program arg1 arg2
# 附加到正在运行的进程
gdb -p <PID>
# 调试 core 文件
gdb ./program core
# 静默启动(不显示欢迎信息)
gdb -q ./program
1.2 编译时加入调试信息 1
2
3
4
5
6
7
8
# GCC/G++ 编译时添加 -g 选项
gcc -g -o program program.c
# 推荐关闭优化,否则调试体验差
gcc -g -O0 -o program program.c
# 使用 gdwarf-4 格式(兼容性更好)
gcc -g -gdwarf-4 -o program program.c
1.3 GDB 内部命令 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 退出 GDB
(gdb) quit
(gdb) q
# 执行 shell 命令
(gdb) shell ls -la
(gdb) !ls -la
# 清屏
(gdb) shell clear
# 帮助
(gdb) help
(gdb) help breakpoints
(gdb) help break
二、程序执行控制 2.1 运行程序 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 运行程序
(gdb) run
(gdb) r
# 带参数运行
(gdb) run arg1 arg2 arg3
# 重新运行(会先终止当前进程)
(gdb) run
# 启动程序但停在第一行
(gdb) start
# 启动并停在 main 函数
(gdb) starti # 停在第一条指令
2.2 单步执行 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 单步执行(进入函数)
(gdb) step
(gdb) s
# 单步执行(不进入函数)
(gdb) next
(gdb) n
# 执行指定步数
(gdb) next 10
(gdb) step 5
# 执行到当前函数返回
(gdb) finish
# 执行到指定行
(gdb) until 50
(gdb) until func_name
# 继续执行到下一个断点
(gdb) continue
(gdb) c
# 继续执行指定次数(跳过当前断点 n 次)
(gdb) continue 5
2.3 执行汇编级单步 1
2
3
4
5
6
7
8
9
10
# 汇编级单步(进入函数)
(gdb) stepi
(gdb) si
# 汇编级单步(不进入函数)
(gdb) nexti
(gdb) ni
# 显示当前汇编指令
(gdb) display/i $pc
三、断点管理 3.1 设置断点 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 在函数处设置断点
( gdb ) break main
( gdb ) b main
# 在文件:行号处设置断点
( gdb ) break file . c : 50
( gdb ) b file . c : 50
# 在当前文件的行号处设置断点
( gdb ) break 100
# 在地址处设置断点
( gdb ) break * 0x08048500
# 条件断点
( gdb ) break main if x > 10
( gdb ) b func if i == 5
# 设置临时断点(触发一次后自动删除)
( gdb ) tbreak main
# 设置硬件断点
( gdb ) hbreak main
# 设置读断点(数据断点)
( gdb ) rwatch variable
# 设置写断点
( gdb ) watch variable
# 设置读写断点
( gdb ) awatch variable
3.2 查看断点 1
2
3
4
5
6
7
8
# 查看所有断点
(gdb) info breakpoints
(gdb) info b
(gdb) i b
# 查看特定断点
(gdb) info breakpoints 1
(gdb) info breakpoints 1-3
3.3 管理断点 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 禁用断点
(gdb) disable 1
(gdb) disable 1-3
# 启用断点
(gdb) enable 1
(gdb) enable 1-3
# 启用断点一次(触发后自动禁用)
(gdb) enable once 1
# 启用断点并在触发后删除
(gdb) enable delete 1
# 删除断点
(gdb) delete 1
(gdb) delete 1-3
(gdb) delete # 删除所有断点
# 清除断点(按位置)
(gdb) clear main
(gdb) clear file.c:50
# 设置断点忽略次数
(gdb) ignore 1 10 # 忽略断点1的前10次触发
3.4 断点命令 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 为断点添加命令(触发断点时自动执行)
(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>print x
>print y
>continue
>end
# 示例:自动打印变量并继续
(gdb) b func
(gdb) commands
>printf "x = %d, y = %d\n", x, y
>continue
>end
四、查看变量与内存 4.1 打印变量 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 打印变量值
( gdb ) print variable
( gdb ) p variable
# 打印表达式
( gdb ) print x + y
( gdb ) print array [ 0 ] + array [ 1 ]
# 打印数组
( gdb ) print array
( gdb ) print array [ 0 ] @ 10 # 打印数组前10个元素
( gdb ) print * array @ 10 # 打印指针指向的10个元素
# 打印字符串
( gdb ) print string
( gdb ) print ( char * ) string
# 打印指定长度字符串
( gdb ) print ( char [ 20 ]) string
# 打印结构体
( gdb ) print struct_var
( gdb ) print struct_var -> member
# 指定格式打印
( gdb ) print / x var # 十六进制
( gdb ) print / d var # 十进制
( gdb ) print / u var # 无符号十进制
( gdb ) print / o var # 八进制
( gdb ) print / t var # 二进制
( gdb ) print / c var # 字符
( gdb ) print / f var # 浮点数
( gdb ) print / a var # 地址
# 打印类型信息
( gdb ) ptype variable
( gdb ) ptype struct_name
# 打印变量大小
( gdb ) print sizeof ( variable )
( gdb ) print sizeof ( struct_name )
4.2 显示变量(自动打印) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 每次停止时自动显示变量
( gdb ) display variable
( gdb ) display / x variable # 十六进制显示
# 查看所有 display
( gdb ) info display
# 禁用 display
( gdb ) disable display 1
# 启用 display
( gdb ) enable display 1
# 删除 display
( gdb ) undisplay 1
( gdb ) delete display 1
4.3 查看内存 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看内存
# x/nfu addr
# n: 显示单元数量
# f: 显示格式 (x/d/u/o/t/c/f/s)
# u: 单元大小 (b=1字节, h=2字节, w=4字节, g=8字节)
( gdb ) x / 10 x 0x20000000 # 10个16进制四字节
( gdb ) x / 20 c & string # 20个字符
( gdb ) x / 10 i $ pc # 10条指令
( gdb ) x / s string_ptr # 字符串
# 查看指定地址
( gdb ) x / 16 xb & variable # variable的前16字节(十六进制)
( gdb ) x / 8 hw & array # array的前8个半字(2字节)
# 查看当前指令
( gdb ) x / i $ pc
( gdb ) x / 5 i $ pc # 当前位置开始的5条指令
4.4 查看寄存器 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看所有寄存器
(gdb) info registers
(gdb) i r
# 查看特定寄存器
(gdb) info registers rax rbx
(gdb) print $rax
(gdb) print $pc
(gdb) print $sp
# 查看浮点寄存器
(gdb) info float
# 查看向量寄存器
(gdb) info vector
五、栈帧操作 5.1 查看调用栈 1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看调用栈
(gdb) backtrace
(gdb) bt
# 查看完整调用栈
(gdb) backtrace full
(gdb) bt full
# 查看指定层数
(gdb) backtrace 5 # 只显示5层
# 查看所有线程的调用栈
(gdb) thread apply all backtrace
5.2 切换栈帧 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查看当前栈帧
(gdb) frame
(gdb) info frame
# 切换到指定栈帧
(gdb) frame 2
(gdb) f 2
# 向上移动(调用者方向)
(gdb) up
(gdb) up 2
# 向下移动(被调用者方向)
(gdb) down
(gdb) down 2
# 查看栈帧信息
(gdb) info frame 2
(gdb) info args # 当前函数参数
(gdb) info locals # 当前函数局部变量
5.3 栈帧图示 1
2
3
4
5
6
7
8
#0 func2 (x=10) at file2.c:25
#1 0x08048500 in func1 (y=20) at file1.c:50
#2 0x08048600 in main () at main.c:100
↑
当前栈帧 (#0)
up 命令移动方向 ←
→ down 命令移动方向
六、源码查看 6.1 查看源码 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 显示当前行附近的代码
(gdb) list
(gdb) l
# 显示指定行
(gdb) list 50
(gdb) list main.c:50
# 显示指定函数
(gdb) list main
(gdb) list file.c:func
# 显示指定范围
(gdb) list 10,30
(gdb) list main.c:10,main.c:30
# 向前/向后翻页
(gdb) list - # 向前
(gdb) list + # 向后
# 设置每次显示的行数
(gdb) set listsize 20
(gdb) show listsize
6.2 源码搜索 1
2
3
4
5
6
# 向前搜索
(gdb) forward-search pattern
(gdb) search pattern
# 向后搜索
(gdb) reverse-search pattern
6.3 反汇编 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 反汇编当前函数
(gdb) disassemble
(gdb) disas
# 反汇编指定函数
(gdb) disassemble main
# 反汇编指定范围
(gdb) disassemble 0x08048500,0x08048600
# 混合源码和汇编
(gdb) disassemble /m main
# 混合源码和汇编(带行号)
(gdb) disassemble /s main
七、修改变量与内存 7.1 修改变量 1
2
3
4
5
6
7
8
9
10
11
# 设置变量值
( gdb ) set variable = 100
( gdb ) set x = 10
( gdb ) set ptr -> member = 5
# 修改数组元素
( gdb ) set array [ 0 ] = 100
# 使用表达式
( gdb ) set x = x + 10
( gdb ) set x += 5
7.2 修改内存 1
2
3
4
5
6
7
# 修改内存
(gdb) set {int}0x20000000 = 100
(gdb) set {char[10]}0x20000000 = "hello"
# 修改寄存器
(gdb) set $rax = 0
(gdb) set $pc = 0x08048500
7.3 跳转执行 1
2
3
4
5
6
# 跳转到指定行
(gdb) jump 50
(gdb) jump file.c:50
# 跳转到指定地址
(gdb) jump *0x08048500
八、多线程调试 8.1 查看线程 1
2
3
4
5
6
7
# 查看所有线程
(gdb) info threads
# 输出示例:
# Id Target Id Frame
# * 1 Thread 0x7ffff7fd0740 (LWP 12345) "program" main () at main.c:10
# 2 Thread 0x7ffff6ffb700 (LWP 12346) "program" 0x00007ffff7bc64e0 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0
8.2 切换线程 1
2
3
4
5
6
7
8
9
# 切换到指定线程
(gdb) thread 2
# 在所有线程执行命令
(gdb) thread apply all info registers
(gdb) thread apply all backtrace
# 在指定线程执行命令
(gdb) thread apply 1-3 info locals
8.3 线程断点 1
2
3
4
5
6
# 设置特定线程的断点
(gdb) break main thread 2
(gdb) break main thread 2 if x > 10
# 设置线程特定断点
(gdb) break file.c:50 thread 2
8.4 线程调度锁定 1
2
3
4
5
6
7
# 设置调度模式
(gdb) set scheduler-locking on # 只运行当前线程
(gdb) set scheduler-locking off # 所有线程都可运行
(gdb) set scheduler-locking step # 单步时只运行当前线程
# 查看当前模式
(gdb) show scheduler-locking
九、多进程调试 9.1 follow-fork 模式 1
2
3
4
5
6
7
# 设置 fork 后跟踪的进程
(gdb) set follow-fork-mode parent # 跟踪父进程(默认)
(gdb) set follow-fork-mode child # 跟踪子进程
# 查看 fork 后是否分离另一个进程
(gdb) set detach-on-fork on # 分离(默认)
(gdb) set detach-on-fork off # 不分离,可以调试两个进程
9.2 查看被调试的进程 1
2
3
4
5
# 查看所有被调试的进程
(gdb) info inferiors
# 切换进程
(gdb) inferior 2
9.3 进程命令 1
2
3
4
5
6
7
8
9
10
11
# 添加一个被调试的进程
(gdb) add-inferior
# 克隆当前进程的调试设置
(gdb) clone-inferior
# 分离进程
(gdb) detach inferior 2
# 杀死进程
(gdb) kill inferior 2
十、观察点(Watchpoint) 10.1 设置观察点 1
2
3
4
5
6
7
8
9
# 写观察点(变量被修改时触发)
( gdb ) watch variable
( gdb ) watch * ( int * ) 0x20000000
# 读观察点(变量被读取时触发)
( gdb ) rwatch variable
# 读写观察点
( gdb ) awatch variable
10.2 观察点管理 1
2
3
4
5
6
7
8
# 查看观察点
( gdb ) info watchpoints
# 删除观察点
( gdb ) delete watch 1
# 条件观察点
( gdb ) watch variable if variable > 100
10.3 观察点示例 1
2
3
4
5
6
7
8
9
10
11
# 调试变量被谁修改的问题
( gdb ) watch x
Hardware watchpoint 1 : x
( gdb ) continue
Continuing .
Hardware watchpoint 1 : x
Old value = 0
New value = 100
func () at main . c : 10
10 x = 100 ;
十一、信号处理 11.1 查看信号处理 1
2
3
4
5
6
7
8
# 查看信号处理设置
( gdb ) info signals
( gdb ) info handle
# 输出示例:
# Signal Stop Print Pass to program Description
# SIGINT Yes Yes No Interrupt
# SIGSEGV Yes Yes Yes Segmentation fault
11.2 设置信号处理 1
2
3
4
5
6
7
8
9
# 设置信号处理方式
# handle signal action...
# stop/nostop: 收到信号时是否停止
# print/noprint: 是否打印信号信息
# pass/nopass: 是否传递给程序
( gdb ) handle SIGINT stop print pass
( gdb ) handle SIGSEGV stop print
( gdb ) handle SIGUSR1 nostop noprint pass
11.3 发送信号 1
2
3
4
5
6
7
# 向程序发送信号
( gdb ) signal SIGUSR1
# 继续执行并发送信号
( gdb ) continue
# Ctrl+C 中断
( gdb ) signal SIGCONT
十二、核心转储(Core Dump) 12.1 生成 Core Dump 1
2
3
4
5
6
7
8
# 启用 core dump
ulimit -c unlimited
# 设置 core dump 格式
echo "/tmp/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
# 运行程序(崩溃时自动生成 core 文件)
./program
12.2 调试 Core Dump 1
2
3
4
5
6
7
8
# 使用 GDB 调试 core 文件
gdb ./program core.12345
# 在 GDB 中
( gdb) bt # 查看崩溃时的调用栈
( gdb) info registers # 查看寄存器状态
( gdb) frame 0 # 切换到崩溃帧
( gdb) info locals # 查看局部变量
12.3 Core Dump 分析流程 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 查看崩溃位置
(gdb) bt
# 2. 切换到崩溃帧
(gdb) frame 0
# 3. 查看源码
(gdb) list
# 4. 查看变量
(gdb) info locals
(gdb) info args
# 5. 分析原因
(gdb) print pointer
(gdb) x/10x pointer
十三、远程调试 13.1 启动 GDB Server 1
2
3
4
5
# 在目标机上启动 gdbserver
gdbserver :1234 ./program
# 附加到进程
gdbserver :1234 --attach <PID>
13.2 连接远程调试 1
2
3
4
5
6
# 在主机上连接
(gdb) target remote 192.168.1.100:1234
# 连接后正常使用 GDB 命令
(gdb) break main
(gdb) continue
13.3 常用远程调试命令 1
2
3
4
5
6
7
8
# 查看远程目标信息
(gdb) info target
# 断开连接
(gdb) disconnect
# 重新连接
(gdb) target remote :1234
十四、脚本与自动化 14.1 GDB 初始化文件 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# ~/.gdbinit 文件
# 设置启动信息
set pagination off
set confirm off
# 历史记录
set history save on
set history size 10000
# 美化打印
set print pretty on
set print array on
set print array-indexes on
# 定义命令
define plist
set $node = $arg0
while $node
print *$node
set $node = $node ->next
end
end
document plist
Print a linked list starting from the given node.
Usage: plist head_pointer
end
# 添加源码路径
directory /path/to/source
14.2 自定义命令 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 定义命令
( gdb ) define print_status
Type commands for definition of " print_status " .
End with a line saying just " end " .
> printf " Current status : % d \ n " , status
> printf " Error code : % d \ n " , error_code
> end
# 添加文档
( gdb ) document print_status
Print the current status and error code .
end
# 使用自定义命令
( gdb ) print_status
14.3 条件断点技巧 1
2
3
4
5
6
7
8
9
10
11
# 复杂条件断点
( gdb ) b func if strcmp ( name , "test" ) == 0
# 调用函数作为条件
( gdb ) b func if check_valid ( ptr )
# 打印并继续
( gdb ) commands
> printf "x= %d , y= %d \n " , x , y
> continue
> end
14.4 执行脚本文件 1
2
3
4
5
# 执行脚本文件
(gdb) source debug.gdb
# 命令行指定
gdb -x debug.gdb ./program
十五、实用技巧 15.1 TUI 模式 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 启动 TUI 模式
gdb -tui ./program
# 在 GDB 中切换 TUI
( gdb) tui enable
( gdb) tui disable
# TUI 窗口操作
( gdb) layout src # 源码窗口
( gdb) layout asm # 汇编窗口
( gdb) layout split # 源码+汇编
( gdb) layout regs # 寄存器窗口
# 切换焦点
( gdb) focus src
( gdb) focus cmd
( gdb) focus regs
# 刷新窗口
( gdb) refresh
15.2 Python 扩展 1
2
3
4
5
6
7
8
9
10
11
12
13
# GDB 内置 Python 解释器
(gdb) python print("Hello")
# 定义 Python 命令
(gdb) python
>class PrintList(gdb.Command):
> def __init__(self):
> super().__init__("plist", gdb.COMMAND_DATA)
> def invoke(self, arg, from_tty):
> # ... 实现逻辑
> pass
>PrintList()
>end
15.3 调试优化代码 1
2
3
4
5
6
7
8
# 显示优化后的变量位置
(gdb) info locals
# 使用 $pc 查找位置
(gdb) x/10i $pc
# 查看寄存器中的值
(gdb) info registers
15.4 常用命令别名 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 在 .gdbinit 中定义别名
define bpl
info breakpoints
end
define bpc
delete $arg0
end
define bpe
enable $arg0
end
define bpd
disable $arg0
end
十六、常用命令速查表 16.1 程序控制 命令 简写 说明 runr运行程序 start启动并停在 main continuec继续执行 nextn单步(不进入函数) steps单步(进入函数) finish执行到函数返回 untilu执行到指定行 quitq退出 GDB
16.2 断点 命令 简写 说明 breakb设置断点 tbreak临时断点 info breakpointsi b查看断点 deleted删除断点 disable禁用断点 enable启用断点 watch设置观察点 condition设置条件
16.3 查看信息 命令 简写 说明 printp打印变量 display自动显示 x查看内存 listl查看源码 backtracebt调用栈 info registersi r寄存器 info locals局部变量 info args函数参数 ptype类型信息
16.4 栈帧操作 命令 简写 说明 framef切换栈帧 up上一帧 down下一帧 info frame栈帧信息
参考资料
Licensed under CC BY-NC-SA 4.0
评论
留言经审核后显示,欢迎留下想法。