除了断点命令(请参见断点命令列表),GDB还提供了两种方法来存储作为一个单元执行的命令序列:用户定义的命令和命令文件。
一、用户自定义命令
用户定义的命令是一系列GDB命令,我们可以使用一个新名称来指定这一串命令。这个过程通过define
命令完成。用户命令可以接受由空格分隔的无限数量的参数。参数在用户命令中通过$arg0…$argN访问。下面是一个普通的例子:
define adder
print $arg0+$arg1+$arg2
end
我们可以这样执行这个命令:
adder 1 2 3
上面就是我们定义adder
的命令,这个命令会打印出三个参数的和。注意,参数是文本替换,因此它们可能引用变量、使用复杂表达式,甚至执行低级函数调用。
此外,$argc参数可能被用来探明到底传递了多少参数。
define adder
if $argc == 2
print $arg0 + $arg1
end
if $argc == 3
print $arg0 + $arg1 +$ arg2
end
end
结合eval命令(请参见eval)可以更轻松地处理数量可变的参数:
define adder
set $i =0
set $sum = 0
while $i < $argc
eval "set $sum = $sum +$arg%d", $i
set $i =$i +1
end
print $sum
end
https://sourceware.org/gdb/current/onlinedocs/gdb/Define.html#Define
二、用户自定义钩子
我们可以定义钩子,这是一种特殊的用户定义命令。每当运行命令foo
时,如果用户定义的命令hook-foo
’存在,则钩子就会在执行foo
前执行(不带参数)。
我们还可以定义在执行命令之后运行的钩子。每当我们运行命令foo
时,如果用户定义的命令hookpost-foo
存在,它将在该命令之后执行(不带参数)。对于同一命令,执行后钩子可以与执行前钩子同时存在。
钩子调用它钩住的命令是有效的。如果发生这种情况,则不会重新执行钩子,从而避免无限递归。
此外,还存在伪命令stop
。定义hook-stop
使程序中每次执行停止时都执行关联的命令(也就是在运行断点命令、打印显示或打印堆栈帧之前)。
例如,要在单步执行时忽略SIGALRM信号,但在正常执行期间正常处理它们,可以定义:
define hook-stop
handle SIGALRM nopass
end
define hook-run
handle SIGALRM pass
end
define hook-continue
handle SIGALRM pass
end
再举一个例子,要在echo命令的开头和结尾定义钩子,并在消息的开头和结尾添加额外的文本,我们可以按照如下的方式定义:
define hook-echo
echo <<<---
end
define hookpost-echo
echo --->>>\n
end
(gdb) echo Hello World
<<<---Hello World--->>>
(gdb)
我们可以为GDB中的任何单字命令定义钩子,但不能为命令别名定义钩子;我们应该为基本命令名定义钩子,例如backtrace而不是bt。我们可以通过将hook-
或hookpost-
添加到命令的最后一个字来钩子多字命令,例如define target hook-remote
“将钩子添加到target remote
。
如果在执行钩子期间发生错误,GDB命令的执行将停止,GDB将发出提示(在您实际键入的命令有机会运行之前)。
如果尝试定义与任何已知命令都不匹配的钩子,则会从define命令得到警告。
https://sourceware.org/gdb/current/onlinedocs/gdb/Hooks.html#Hooks