mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-02-03 23:40:14 +08:00
Merge pull request #28167 from lkxed/20221208-2-7-pro-tips-for-using-the-GDB-step-command
[手动选题][tech]: 20221208.2 ⭐️⭐️ 7 pro tips for using the GDB step command.md
This commit is contained in:
commit
c7fda8a95c
@ -0,0 +1,255 @@
|
||||
[#]: 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: " "
|
||||
[#]: 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 it’s disabled but you can enable it later if it’s 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
|
Loading…
Reference in New Issue
Block a user