本文首先介绍用于自动化调试的gdb脚本的基本语法和基本用法,然后给出程序实例和调试实例。
在使用gdb调试程序的时候,如果想让调试自动化,该怎么办呢?
比如,想关闭 confirm,关闭 pagination,打开 print pretty, 设置 system root 为当前目录,等等。
如果是每次运行gdb都希望自动实现这些简单的设置,那么可以写在 ~/.gdbinit 文件中。如下:
#~/.gdbinit
set sysroot
set confirm off
set pagination off
set print pretty
如果不是一个普通的需求,而是希望对一个特定的程序做一些自动的调试工作,比如,当遇到循环的时候,在循环体内自动地break和打印某些变量,那么该如何做呢?
编写一个gdb的命令脚本即可。
井号 # 表示注释
set
1> 设置gdb的一些选项的值,如前面提及的pagination等
如果要查看当前的值,可以使用show命令,比如: show pagination
2> 创建调试使用的变量
set $a = i
不带$的变量是被调试程序中的变量,如这里的i; 带$的变量为调试过程中定义的变量,如这里的$a
所有在gdb中创建的变量都是全局的
其他的例子还有:
(gdb) set $i = (char *)("Hello")
(gdb) print $i
$1 = 0x7ffff7fddf00 "Hello"
(gdb) printf "%s\n", $i
Hello
3> 访问寄存器
set $a = $eax
p $a
4> 修改寄存器
set $eax = 5
5> 修改内存
set *(unsigned char *)$addr = 0x90
define func_name
end
document func_name
# write documents here
end
echo Hello\n
printf "a=%d\n", 10
# e.g. if i == 10
if
# do something
else
# do other things
end
while
# do something
end
举例:
set $i = 10
while $i > 0
printf "%d\n", $i
set $i = $i - 1
end
如,run, continue, info locals 等等
这一点是很常用的,尤其是在调试for循环的时候。
先看一个最简单的实例
break function_name
command 1
backtrace
continue
end
以上代码,就是在指定的函数开始处设断点,当运行到此处后,打印backtrace,然后继续运行。
再看一个更加实用一点的例子:
set pagination off
set logging on gdb.output
set $var = 0
# 带 if 的 break 语句
break function1 if param1 == 32
command 1
print param2
print param3->member1
continue
end
break file.c:142 if x > 4
command 2
print y
call checker_function
continue
end
# 带 if 以及 ++ 运算的 break 语句
break function2 if $var++ < 3
command 3
print $var
backtrace full
continue
end
run
set logging off
quit
以上这段代码,可以保存进一个gdb脚本文件中了,比如,命名为 mycmd.gdb
那么如何使用gdb脚本呢,如上述的 mycmd.gdb?
有2种方法:
方法一: 在gdb的interactive界面运行 source mycmd.gdb
(gdb) file test.exe
(gdb) source mycmd.gdb
方法二: 在命令行中运行 gdb 的 batch 模式命令
gdb --batch --command=cmd.gdb --args test.exe
三点说明:
“–batch” 的含义是,该gdb命令将在命令行中运行,运行结束后,光标仍停留在命令行;
假设不加 “–batch”, 则命令执行结束后,会停留再gdb的互动界面 (假设脚本最后没有 quit 语句。因以上脚本最后有quit,所以即使不在batch模式,也依然会退出gdb到达命令行。)
“–command” 指定gdb脚本
若已在 “–args” 中指定了运行参数,则不要在gdb脚本的 run 命令后再指定运行参数了;
否则,run命令中的运行参数会覆盖 “–args” 中的运行参数。
以下给出一个C语言的示例程序,再给出一个gdb脚本,最后给出该脚本的运行结果。
C语言示例程序如下:
// test.c
// gcc -g test.c -o test.exe
#include
#include
int icount = 1; // default value
int main(int argc, char *argv[])
{
int i, b;
if (argc == 2) {
icount = atoi(argv[1]);
}
i = icount;
while (i > -1) {
b = 5 / i;
printf(" 5 / %d = %d \n", i, b );
i--;
}
printf("Finished\n");
return 0;
}
gdb命令文件 cmd.gdb
set $LINE_BP_1 = 20
set $LINE_BP_2 = 19
# at entry point - cmd1
b main
commands 1
print argc
continue
end
# printf line - cmd2
b test.c:$LINE_BP_1
commands 2
p i
p b
continue
end
# int b = line - cmd3
b test.c:$LINE_BP_2
commands 3
p i
p b
continue
end
# show arguments for program
show args
run
执行gdb自动运行命令:
gdb --batch --command=cmd.gdb --args test.exe 3
执行效果如下:
$gdb --batch --command=cmd.gdb --args test.exe 3
Breakpoint 1 at 0x719: file test.c, line 10.
Breakpoint 2 at 0x74f: file test.c, line 17.
Breakpoint 3 at 0x743: file test.c, line 16.
Argument list to give program being debugged when it is started is "3".
Missing separate debuginfo for /lib64/ld-linux-x86-64.so.2
Try: zypper install -C "debuginfo(build-id)=9487b554bdea197d4813797d7c37491ae1983345"
Missing separate debuginfo for /lib64/libc.so.6
Try: zypper install -C "debuginfo(build-id)=c688e67ac1e22ad79f4fd60d7fb012a267e83a29"
Breakpoint 1, main (argc=2, argv=0x7fffffffe188) at test.c:13
13 if (argc == 2) {
$1 = 2
Breakpoint 3, main (argc=2, argv=0x7fffffffe188) at test.c:19
19 b = 5 / i;
$2 = 3
$3 = 0
Breakpoint 2, main (argc=2, argv=0x7fffffffe188) at test.c:20
20 printf(" 5 / %d = %d \n", i, b );
$4 = 3
$5 = 1
5 / 3 = 1
Breakpoint 3, main (argc=2, argv=0x7fffffffe188) at test.c:19
19 b = 5 / i;
$6 = 2
$7 = 1
Breakpoint 2, main (argc=2, argv=0x7fffffffe188) at test.c:20
20 printf(" 5 / %d = %d \n", i, b );
$8 = 2
$9 = 2
5 / 2 = 2
Breakpoint 3, main (argc=2, argv=0x7fffffffe188) at test.c:19
19 b = 5 / i;
$10 = 1
$11 = 2
Breakpoint 2, main (argc=2, argv=0x7fffffffe188) at test.c:20
20 printf(" 5 / %d = %d \n", i, b );
$12 = 1
$13 = 5
5 / 1 = 5
Breakpoint 3, main (argc=2, argv=0x7fffffffe188) at test.c:19
19 b = 5 / i;
$14 = 0
$15 = 5
Program received signal SIGFPE, Arithmetic exception.
0x0000555555554749 in main (argc=2, argv=0x7fffffffe188) at test.c:19
16 b = 5 / i;
笔者的gdb版本为8.1,试验平台为SUSE15.
(完)