TranslateProject/sources/tech/20221208.2 ⭐️⭐️ 7 pro tips for using the GDB step command.md
2022-12-10 10:46:05 +08:00

256 lines
8.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[#]: subject: "7 pro tips for using the GDB step command"
[#]: via: "https://opensource.com/article/22/12/gdb-step-command"
[#]: author: "Alexandra https://opensource.com/users/ahajkova"
[#]: collector: "lkxed"
[#]: translator: "chai001125"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
7 pro tips for using the GDB step command
======
A debugger is software that runs your code and examines any problems it finds. [GNU Debugger][1] (GBD) is one of the most popular debuggers, and in this article, I examine GDB's `step` command and related commands for several common use cases. Step is a widely used command but there are a few lesser known things about it which might be confusing. Also, there are ways to step into a function without actually using the `step` command itself such as using the less known `advance` command.
### No debugging symbols
Consider a simple example program:
```
#include <stdio.h>
int num() {
return 2;
}
void bar(int i) {
printf("i = %d\n", i);
}
int main() {
bar(num());
return 0;
}
```
If you compile without the debugging symbols first, set a breakpoint on `bar` and then try to step within it. The GDB gives an error message about 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 ()
```
### Stepi
It is still possible to step inside the function that has no line number information but the `stepi` command should be used instead. Stepi executes just one instruction at a time. When using GDB's `stepi` command, it's often useful to first do `display/i $pc`. This causes the program counter value and corresponding machine instruction to be displayed after each step:
```
(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 <bar+4>: sub $0x10,%rsp
```
In the above `display` command, the `i` stands for machine instructions and `$pc` is the program counter register.
It can be useful to use info registers and print some register contents:
```
(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 <bar+8>: mov %edi,-0x4(%rbp)
```
### Complicated function call
After recompiling the example program with debugging symbols you can set the breakpoint on the `bar` call in main using its line number and then try to step into `bar` again:
```
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());
```
Now, let's step into`bar()`:
```
(gdb) step
num () at exmp.c:4
4 return 2;
```
The arguments for a function call need to be processed before the actual function call, so `num()` is expected to execute before `bar()`is called. But how do you step into the `bar` as was desired? You need to use the `finish` command and `step` again:
```
(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);
```
### Tbreak
The `tbreak` command sets a temporary breakpoint. It's useful for situations where you don't want to set a permanent breakpoint. For example, if you want to step into a complicated function call like `f(g(h()), i(j()), ...)` , in such a case you need a long sequence of `step/finish/step` to step into `f` . Setting a temporary breakpoint and then using continue can help to avoid using such sequences. To demonstrate this, you need to set the breakpoint to the `bar` call in `main` as before. Then set the temporary breakpoint on `bar`.  As a temporary breakpoint it is automatically removed after being hit:
```
(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.
```
After hitting the breakpoint on the call to `bar` and setting a temporary breakpoint on `bar`, you just need to continue to end up in  `bar`.
```
(gdb) continue
Continuing.
Temporary breakpoint 2, bar (i=2) at exmp.c:9
9 printf("i = %d\n", i);
```
### Disable command
Alternatively, you could set a normal breakpoint on `bar` , continue, and then disable this second breakpoint when it's no longer needed. This way you can achieve the same results as with the `tbreak` with one extra command:
```
(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
```
As you can see, the `info breakpoints`  command displays `n` under `Enb`which means its disabled but you can enable it later if its needed again.
```
(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
```
### Advance location
Another option you can use is an `advance` command. Instead of `tbreak bar ; continue` , you can simply do `advance bar` . This command continues running the program up to the given location.
The other cool thing about `advance` is that if the location that you try to advance to is not reached, GDB will stop after the current frame's function finishes. Thus, execution of the program is constrained:
```
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);
```
### Skipping a function
Yet another way to step into the `bar,` avoiding `num`, is using the `skip` command:
```
(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);
```
To know which functions are currently skipped,  `info skip` is used.  The `num` function is marked as enabled to be skipped by `y`:
```
(gdb) info skip
Num Enb Glob File RE Function
1 y n <none> n num
```
If `skip` is not needed any more it can be disabled (and re-enabled later) or deleted altogether. You can add another `skip` and disable the first one and then delete them all. To disable a certain `skip`, its number has to be specified, if not specified, each `skip`is disabled. It works the same for enabling or deleting a `skip`:
```
(gdb) skip bar
(gdb) skip disable 1
(gdb) info skip
Num Enb Glob File RE Function
1 n n <none> n num
2 y n <none> n bar
(gdb) skip delete
(gdb) info skip
Not skipping any files or functions.
```
### GDB step command
Using GDB's `step` command is a useful tool for debugging your application. There are several ways to step into even complicated functions, so give these GDB techniques a try next time you're troubleshooting your code.
--------------------------------------------------------------------------------
via: https://opensource.com/article/22/12/gdb-step-command
作者:[Alexandra][a]
选题:[lkxed][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/ahajkova
[b]: https://github.com/lkxed
[1]: https://opensource.com/article/21/3/debug-code-gdb