常见指令
这里记录常用的指令和基本使用方式。
程序运行控制相关指令
显示带行号的源码
使用list(l)
命令可以显示源代码,方便确定行号,之后打断点可以用到。
程序启动和重启
使用 run
或 start
指令,start会在main函数处停下,run会一直运行直到第一个断点。(start相当于在main函数处放了一个断点再run)。run命令简写为r。
另外,重定向功能也是支持的,包括输入重定向,输入重定向,如 run > outpirint.txt
。
程序继续运行
在遇到断点停下后,(可以进行一些单步执行命令),继续运行程序,使用continue
命令,简写为c。
环境设置
经常需要在程序运行前设置一些环境,如启动参数,环境变量,工作目录等。
设置程序启动参数
1
2
3
4
5
(gdb)set args [arg1] [arg2] [...]
# 或
(gdb) run [arg1] [arg2] [...]
# 查看已设置的参数
(gdb) show args
如果设置时一个都不填,就是没有参数。
设置环境变量
1
2
3
4
5
(gdb) set environment VAR=value
# 查看所有环境变量
(gdb) show environment
# 查看指定环境变量
(gdb) show environment VAR
对于环境的设置,如果频繁,可以使用初始化文件:创建好文件并将需要的一些初始化命令写入,如设置参数,环境变量等,然后在启动gdb时,指定该 命令文件即可,gdb会自动执行里面的指令。
1
2
vim ./testapp.gdbini
gdb -x ./testapp.gdbini ./testapp
还有一个~/.gdbinit
文件,该文件是用户的全局gdb初始化文件,效果同理,对该用户的所有gdb生效。
断点
break
指令是一个用于设置断点的指令。断点是在程序中指定的位置,当程序执行到该位置时,会暂停执行并返回给调试器,以便检查程序状态、变量的值 以及执行路径等。break指令简写为b。
设置断点:
break <location>
:在指定的代码位置设置断点。位置可以是函数名、行号或文件名中的函数名/行号组合。例如:
1
2
3
4
5
6
break 123 // 在当前文件的123行设置断点
break file.c:10 // 在 file.c 文件的第 10 行设置断点
break my_function // 在 my_function 函数入口处设置断点
break file.c:func2 // 在 file.c 中的func2函数处设置断点
break *0x12345678 // 在地址 0x12345678 处设置断点,这里的*是一定要写的
break *(&gb_a) // 在全局变量gb_a出打断点
条件断点:
break <location> if <condition>
:设置条件断点,仅当condition
条件满足时才会触发断点,即停下。例如:
1
break main if argc > 5 // 仅当 argc 大于 5 时,在 main 函数处设置断点
如果要修改条件,可以使用
1
condition <breakpoint-number> <new-condiftion>
临时断点:
tbreak <location>
:设置临时断点,该断点只会触发一次,触发后自动删除,其他同普通的break
指令。
特殊的正则表达式断点
rbreak
指令,这个仅对C/C++函数有效,会在函数的开头设置断点。例如:
1
2
# 为所有的 mytestfunc_开头的函数设置断点。
rbreak mytestfunc_*
列出断点:
info breakpoints
:列出当前所有已设置的断点。可以写为 info b
。里面有一个断点的序号,用于管理断点。
禁用和启用断点:
disable <breakpoint-number>
:禁用指定编号的断点。
enable <breakpoint-number>
:启用指定编号的断点。
enable
:启用所有已禁用的断点。
断点的Num可以通过 info b
指令列出查看。
删除断点:
使用delete
或clear
指令。
delete <breakpoint-number>
:删除指定编号的断点。
clear <location>
:删除指定位置的断点。
clear
:删除所有已设置的断点。
忽略断点N次
可以使用ignore
指令忽略count次断点。
ignore <breakpoint-number> <count>
观察点(监视点)
watch
指令是一个用于监视变量或表达式的指令。它允许您在程序执行期间跟踪特定变量或表达式的值,并在该值发生更改时暂停程序执行。 通常监视全局变量多一些,局部变量在栈退出后就消失了,监视不到。
监视变量:
watch <variable>
:监视指定的变量,并在其值发生更改时暂停程序执行。
watch <expression>
:监视指定的表达式,并在其值发生更改时暂停程序执行。
例如:
1
2
3
4
watch my_variable // 监视名为 my_variable 的变量
watch my_array[i] // 监视 my_array 数组中索引为 i 的元素
watch ptr_age // 监视 ptr_age 指针变量
watch *ptr_age // 监视 ptr_age 指针变量对应的值
条件监视:
watch <expression> if <condition>
:设置条件监视,仅当条件满足时才会停止。例如:
1
watch counter if counter > 100 // 仅当 counter 大于 100 时进行监视
观察点类型:
watch
:设置读/写观察点,当变量被读取或写入时触发监视。
rwatch
:设置读取观察点,当变量被读取时触发监视。
awatch
:设置写入观察点,当变量被写入时触发监视。
例如:
1
2
3
watch my_variable // 读/写观察点
rwatch my_variable // 读取观察点
awatch my_variable // 写入观察点
列出/禁用和启用/删除监视点:
相关用法和break指令的用法相似。
info watchpoints
:列出当前所有已设置的监视点。
disable <watchpoint-number>
:禁用指定编号的监视点。
enable <watchpoint-number>
:启用指定编号的监视点。
delete <watchpoint-number>
:删除指定编号的监视点。
监视点类型说明
监视点分硬件监视点(hardware watchpoint)
和软件监视点(software watchpoint)
,它们的实现有区别。
在实现方式上,软件监视点是GDB调试器每次执行指令后,去检测目标变量(表达式)的值是否发生改变,这样实现的,相当于是“实时都会检测“的方式,所以对程序性能有影响(尤其是有大量循环的场景)。 而硬件监视点,是配合硬件实现的,系统会为GDB调试器提供少量寄存器,并在变量更改时触发中断,大致这样配合完成监视任务的。所以,硬件监视点的性能肯定比软件监视点高。 但相对的,硬件监视点需要硬件支持才行,(x86和arm硬件都有支持),软件监视点没有这样的限制。
在支持数量上,软件监视点的数量通常都比硬件监视点多,软件监视点的数量仅受限于系统资源和GDB的设置,硬件监视点受限于硬件情况。
对于监控类型上,软件监视点可以监视更多的变量和表达式,更强大灵活,硬件监视点主要监视内存地址,比如全局变量。
在使用 GDB 进行调试时,可以通过 set can-use-hw-watchpoints on
命令来启用硬件监视点。(如果支持)。GDB 会尽力使用硬件监视点,但如果达到限制或不适用,则会使用软件监视点。 选项默认是开启的。show can-use-hw-watchpoints
命令来查看当前系统是否支持硬件监视点。
捕获点catch
catch
是一个用于捕捉异常和信号的命令。它允许设置捕获点,以便在程序中发生异常或特定信号时暂停执行并返回给调试器。
捕捉异常:
catch throw
:在发生 C++ 异常时暂停执行。 catch catch
:在 C++ 异常被捕获时暂停执行。 catch catch throw
:同时捕获异常的抛出和捕获。
例如:
1
2
3
catch throw // 在发生 C++ 异常时暂停执行
catch catch // 在 C++ 异常被捕获时暂停执行
catch catch throw // 同时捕获异常的抛出和捕获
捕捉信号:
catch signal <signal-name>
:在指定信号发生时暂停执行。可以使用信号名称或信号编号。
例如:
1
2
catch signal SIGSEGV // 在发生 SIGSEGV(段错误)信号时暂停执行
catch signal 11 // 在发生信号编号为 11 的信号时暂停执行
捕捉系统调用:
catch syscall <syscall-name>
:在执行指定的系统调用时暂停执行。
例如:
1
catch syscall open // 在执行 open 系统调用时暂停执行
条件捕获
catch <event> if <condition>
:设置条件捕获,仅当条件满足时才会触发捕获。对上面三个类型适用。示例:
1
catch throw if my_variable > 10 // 仅当 my_variable 大于 10 时进行捕获
更多捕获类型查看 (gdb) help catch
。
自动化调试命令
可以在断点停下时,自动执行一些用户自定义的命令,典型场景就是断点停下后,打印xx变量的值,通常都是手动打印,使用commands
可以实现自动打印:
1
2
3
4
5
6
7
8
commands <breakpoint-number>
... command-list ...
end
commands
printf "x is %d ",x // 格式和C中的printf 有一点不一样,必须用gdb中的写法
continue
end
测试示例
1
2
3
4
5
6
7
8
9
10
11
(gdb) b main if gb_a > 0
(gdb) info b
Num Type Disp Enb Address What
4 breakpoint keep y 0x0000555555555149 in main at ./test.c:7
stop only if gb_a > 0
(gdb) commands 4
Type commands for breakpoint(s) 4, one per line.
End with a line saying just "end".
>printf "gb_a is %d",gb_a
>end
(gdb) r
要清除,重新设置命令集为空即可。
状态查看
在程序停止/暂定运行后,可以查看程序的状态,内存变量,寄存器信息等
1
2
# 查看进程状态
(gdb)info program
参考
man gdb