gdb是什么意思(GDB 的 7 个单步调试命令)

2023-03-24 21:12 资讯百科 投稿:运河边百科网

gdb是什么意思(GDB 的 7 个单步调试命令)

即使是复杂的函数,也有几种方法可以单步调试,所以下次在排除代码故障时,可以尝试一下这些 GDB 技术。

调试器是一个可以运行你的代码并检查问题的软件。GNU Debugger(GBD)是最流行的调试器之一,在这篇文章中,我研究了 GDB 的step命令和其他几种常见情况的相关命令。step是一个被广泛使用的命令,但它有一些人们不太了解的地方,可能会使得他们十分困惑。此外,还有一些方法可以在不使用step命令的情况下进入一个函数,比如使用不太知名的advance命令。

1、无调试符号

考虑以下这个简单的示例程序:

#include 

如果你在没有 调试符号debugging sysbols 的情况下进行编译(LCTT 译注:即在使用 gcc编译程序时没有写-g选项),然后在bar上设置一个断点,然后尝试在这个函数内使用step来单步执行语句。GDB 会给出一个 没有行号信息no line number information 的错误信息。

gcc exmp.c -o exmp
gdb ./exmp
(gdb) b bar
Breakpoint 1 at 0x401135
(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, 0x0000000000401135 in bar 
(gdb) step
Single stepping until exit from function bar,
which has no line number information.
i = 2
0x0000000000401168 in main 

2、stepi 命令

但是你仍然可以在没有行号信息的函数内部单步执行语句,但要使用 stepi命令来代替stepstepi一次只执行一条指令。当使用 GDB 的stepi命令时,先做display/i $pc通常很有用,这会在每一步之后显示程序计数器program counter 的值和相应的机器指令machine instruction:

(gdb) b bar
Breakpoint 1 at 0x401135
(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, 0x0000000000401135 in bar 
(gdb) display/i $pc
1: x/i $pc
=> 0x401135 

在上述的 display命令中,i代表机器指令,$pc表示程序计数器寄存器(即 PC 寄存器)。

使用 info registers命令,来打印寄存器的内容,也是十分有用的。

(gdb) info registers
rax 0x2 2
rbx 0x7fffffffdbc8 140737488346056
rcx 0x403e18 4210200
(gdb) print $rax
$1 = 2
(gdb) stepi
0x0000000000401139 in bar 
1: x/i $pc
=> 0x401139 

3、复杂的函数调用

在带调试符号的 -g选项,重新编译示例程序后,你可以使用行号在mainbar调用上设置断点,然后再单步执行bar函数的语句:

gcc -g exmp.c -o exmp
gdb ./exmp
(gdb) b exmp.c:14
Breakpoint 1 at 0x401157: file exmp.c, line 14.
(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, main  at exmp.c:14
14 bar(num);

接下来,用 step,来单步执行bar函数的语句:

(gdb) step
num  at exmp.c:4
4 return 2;

函数调用的参数需要在实际的函数调用之前进行处理,bar函数的参数是num函数,所以num会在bar被调用之前执行。但是,通过 GDB 调试,你怎么才能如愿以偿地进入bar函数呢?你可以使用finish命令,并再次使用step命令。

(gdb) finish
Run till exit from #0 num  at exmp.c:4
0x0000000000401161 in main  at exmp.c:14
14 bar(num);
Value returned is $1 = 2
(gdb) step
bar (i=2) at exmp.c:9
9 printf("i = %d\n", i);

4、tbreak 命令

tbreak命令会设置一个临时断点。如果你不想设置永久断点,那么这个命令是很有用的。举个例子??,你想进入一个复杂的函数调用,例如f(g(h), i(j), ...),在这种情况下,你需要一个很长的step/finish/step序列,才能到达f函数。如果你设置一个临时断点,然后再使用continue命令,这样就不需要以上的序列了。为了证明这一点,你需要像以前一样将断点设置在mainbar调用上。然后在bar上设置临时断点。当到达该临时断点后,临时断点会被自动删除。

(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, main  at exmp.c:14
14 bar(num);
(gdb) tbreak bar
Temporary breakpoint 2 at 0x40113c: file exmp.c, line 9.

在调用 bar的时候遇到断点,并在bar上设置临时断点后,你只需要使用continue继续运行直到bar结束。

(gdb) continue
Continuing.
Temporary breakpoint 2, bar (i=2) at exmp.c:9
9 printf("i = %d\n", i);

5、disable 命令

类似地,你也可以在 bar上设置一个正常的断点,然后执行continue,然后在不再需要第二个断点时,使用disable命令禁用这个断点,这样也能达到与tbreak相同的效果。

(gdb) b exmp.c:14
Breakpoint 1 at 0x401157: file exmp.c, line 14.
(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, main  at exmp.c:14
14 bar(num);
(gdb) b bar
Breakpoint 2 at 0x40113c: file exmp.c, line 9.
(gdb) c
Continuing.
Breakpoint 2, bar (i=2) at exmp.c:9
9 printf("i = %d\n", i);
(gdb) disable 2

正如你所看到的,info breakpoints命令在Enb列下显示为n,这意味着这个断点已被禁用。但你也能在再次需要这个断点时,再启用它。

(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000401157 in main at exmp.c:14
breakpoint already hit 1 time
2 breakpoint keep n 0x000000000040113c in bar at exmp.c:9
breakpoint already hit 1 time
(gdb) enable 2
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040116a in main at exmp.c:19
breakpoint already hit 1 time
2 breakpoint keep y 0x0000000000401158 in bar at exmp.c:14
breakpoint already hit 1 time

6、advance 命令运行程序到指定的位置

另一个进入函数内部的方法是 advance命令。你可以简单地用advance bar,来代替tbreak bar ; continue。这一命令会将程序继续运行到指定的位置。

advance命令的一个很棒的地方在于:如果程序并没有到达你试图进入的位置,那么 GDB 将在当前函数运行完成后停止。因此,程序的执行会受到限制:

Breakpoint 1 at 0x401157: file exmp.c, line 14.
(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, main  at exmp.c:14
14 bar(num);
(gdb) advance bar
bar (i=2) at exmp.c:9
9 printf("i = %d\n", i);

7、skip 命令

进入 bar函数的另一种方式是使用skip num命令:

(gdb) b exmp.c:14
Breakpoint 1 at 0x401157: file exmp.c, line 14.
(gdb) skip num
Function num will be skipped when stepping.
(gdb) r
Starting program: /home/ahajkova/exmp
Breakpoint 1, main  at exmp.c:14
14 bar(num);
(gdb) step
bar (i=2) at exmp.c:9
9 printf("i = %d\n", i);

请使用 info skip命令,来了解 GDB 跳过了哪些函数。num函数被标记为y,表示跳过了num函数:

(gdb) info skip
Num Enb Glob File RE Function
1 y n 

如果不再需要 skip,可以禁用(并稍后重新启用)或完全删除它。你可以添加另一个skip,并禁用第一个skip,然后全部删除。要禁用某个skip,必须指定其编号(例如,skip disable 1),如果没有指定,则会禁用所有的skip。启用或删除skip的工作原理相同:

(gdb) skip bar
(gdb) skip disable 1
(gdb) info skip
Num Enb Glob File RE Function
1 n n 

GDB 的 step 命令

使用 GDB 的 step命令是调试程序的一个有用工具。即使是复杂的函数,也有几种方法可以单步调试这些函数,所以下次你在排除代码问题的时候,可以尝试一下这些 GDB 技术。

via: https://opensource.com/article/22/12/gdb-step-command

作者:Alexandra选题:lkxed译者:chai001125校对:wxy

本文由 LCTT原创编译,Linux中国荣誉推出

声明:运河边百科网所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流。若您的权利被侵害,请联系站长删除。
加载中...