[#]: 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 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 : 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 : 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 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 n num 2 y n 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