GDB之常用命令介绍
GDB是一个由GNU开源组织发布的,基于命令行的、功能强大的程序调试工具。可以让开发者能看到程序在执行时“内部”发生了什么,或者程序崩溃的现场。下图是gdb的吉祥物--弓箭鱼。
GDB主要做以下4种事情:
- 启动程序
- 使程序在指定条件下停止(比如打断点)
- 当程序停止时,检查发生了什么
- 改变程序的内容,这样可以方便debug程序
1 gdb常用命令
以下主要讲一些gdb的常用命令,按照功能进行简单的区分。
程序运行相关:
命令 | 命令缩写 | 命令说明 |
---|---|---|
run | r | 从开始运行一个待调试的程序,直到遇见断点或退出,每执行一次就会重开始执行 |
continue | c | 让暂停的程序继续运行,直至遇到下一个断点 |
start | start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行,相当于在main函数打断点然后run)。 | |
quit | q | 退出gdb调试 |
next | n | 让 gdb跳到下一条命令去执行,并不一定是下一行,而是根据程序逻辑跳转到相应的位置 |
step | s | 单步执行,遇到函数会进入 |
until | u | 运行到指定行停下来 |
finish | fin | 结束当前调用函数(直到当前函数运行完毕返回再返回),回到上一层调用函数处 |
return | return | 结束当前调用函数并返回指定值,到上一层函数调用处 |
jump | j | 将当前程序执行流跳转到指定行或地址 |
断点相关:
命令 | 命令缩写 | 命令说明 |
---|---|---|
break | b | 添加断点,可带如下参数: linenum 本地行号,即list命令可见的行号 filename:linenum 指定个文件的行号 function 函数,可以是自定义函数也可是库函数,如open filename:function 指定文件中的函数 condtion 条件 *address 地址,可是函数,变量的地址, |
delete | d | 删除断点,参数格式是基于标识符的,不带参数时删掉所有断点 |
clear | 清除断点,参数格式与break相同 | |
enable | enable | 启用某个断点 |
disable | disable | 禁用某个断点 |
watch | watch | 监视某一个变量或内存地址的值是否发生变化,可通过delete删除 |
tbreak | tb | 零时断点,设置方法与break相同,只不过tbreak只在断点停一次,过后会自动将断点删除 |
查看变量或内存:
命令 | 命令缩写 | 命令说明 |
---|---|---|
p | 打印变量或寄存器值 | |
info | i | 查看断点 / 线程等信息 |
examine | x | 以指定格式查看内存 |
display | 会在每次暂停的时候输出表达式的值,display 会根据指定的模式自动选择使用 x 或是 print,取消使用undisplay n,不带参数将取消所有的 | |
list | l | 显示源码清单 |
disassemble | dis | 查看汇编代码 |
backtrace | bt | 查看当前线程的调用堆栈 |
dump | dump 一段内存内容:dump memory <filename> <start-address> <end-address> |
设置变量、寄存器或内存:
命令 | 命令缩写 | 命令说明 |
---|---|---|
set val i = 5 | 将变量i的值设置为5 | |
set val $pc = 0xxxxx | 将pc寄存器设置为某值 | |
set {int}&i=5 | 同样是将变量i的值设置为5,改变地址中的值,等价于set *(int *)&i=5 | |
set {int} 0xA0000000=5 | 改写内存0xA0000000 处的值为5 |
2 常用命令举例
2.1 print info x display等命令的区别
常用的print指令:
命令 | 作用 |
---|---|
p var | 打印变量var,变量可以是整数、浮点、字符串,数组、结构体变量等 |
p <表达式> | 例如:p sizeof(long) 打印系统long类型所占的字节数 |
p i=10 | 改变变量的值i=10 |
常用的info指令:
命令 | 作用 |
---|---|
info args | 输出入参:argc与argv |
info b | 查看断点情况 |
info watchpoints | 查看观察点情况 |
info display | 显示display 命令查看的目标变量或表达式 |
info reg a4 | 查看寄存器a4, info reg打印所有寄存器 |
常用x指令:
查看内存命令语法为:
x /<Nuf> <addr>
# N 要打印的单元数,可以为负值,表示往前数
# u表示每个单元的大小(b(byte), h(halfword), w(word), g(giant, 8 bytes))
# f表示打印的格式(o(octal), x(hex), d(decimal), u(unsigned decimal),t(binary), f(float), a(address),
# i(instruction), c(char), s(string)and z(hex, zero padded on the left))
例如:
命令 | 作用 |
---|---|
x /16x addr | 以16进制显示地址以addr为起始地址的 16个值 |
x /-16x addr | 以16进制显示地址以addr为起始地址的往前数(倒着数)16个值 |
x /i $pc | /i 表示以机器指令显示当前pc处的指令 |
display命令:
display 命令也用于调试阶段查看某个变量或表达式的值,区别是会在每次暂停的时候输出表达式的值,display 会根据指定的模式自动选择使用 x 或是 print,这样方便我们观察变量。
3 调试中遇见的一些问题
3.1 打开gdb的日志功能
当我们在调试一个复杂的程序,gdb过程比较多,我们可以开启gdb的日志功能记录我们使用的gdb命令以及输出,记录在当前文件夹的gdb.txt中。
# 打开
set logging on
# 关闭
set logging off
3.2 gdb的TUI模式(Text User Interface)
在终端界面(TUI, Text User Interface)模式下, GDB可以和Visual Studio或者CLion一样像IDE一下显示和跟踪代码。
gdb -tui
# 或可在运行的过程中,执行:
Ctrl + x + a 或 tui enable
# 关闭tui模式同样执行 Ctrl + x + a 或tui disable
另外需要注意一个细节:
# 有个细节需要注意,此时的上下按键被锁定到了源码位置,如果想上下更新命令,需要如下快捷键:
Ctrl + n,下一命令(Next)
Ctrl + p,上一命令(Prev)
# 焦点切换:
focus next,切换到命令行。
focus prev,切换至源码。
进入后可食用命令行:layout用于分割窗口,可以一边查看代码,一遍测试。
layout src # 显示源代码窗口
layout asm # 显示汇编窗口
layout regs # 显示源代码/汇编和寄存器窗口
layout split # 显示源代码/汇编窗口
Ctrl+x后按2 #切换窗口类型, 可试一下Ctrl+x后按1
3.3 GDB远程调试方法
gdb远程调试用到了gdbserver,它允许gdb与调试的程序运行在不同的机器上,其实就是一个CS系统。
# 目标端开启gdbserver,启动端口
gdbserver host:2345
# 主机端运行gdb,并连接目标端口
gdb
target remote host:1234
load xxx.elf
# 查看v0-v31寄存器、vl寄存器
info reg v0
info reg vl
参考: