mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge pull request #28232 from chai001125/chai001125-patch-1
translated
This commit is contained in:
commit
2bba990149
@ -1,255 +0,0 @@
|
||||
[#]: 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 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
|
@ -0,0 +1,256 @@
|
||||
[#]: 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: " "
|
||||
|
||||
GDB 进入函数内部的 7 个命令
|
||||
======
|
||||
|
||||
>**调试器**是一个可以运行你的代码并检查问题的软件。[GNU Debugger][1](GBD)是最流行的调试器之一,在这篇文章中,我研究了 **GDB 进入函数内部的几个命令**,包含了 **`step` 命令**和其他几个**常见的 GDB 命令**。`step` 是一个被广泛使用的命令,但它有一些人们不太了解的地方,可能会使得他们十分困惑。此外,还有一些方法可以**在不使用 `step` 命令的情况下进入一个函数**,比如使用不太知名的 `advance` 命令。
|
||||
|
||||
### 1、无调试符号
|
||||
|
||||
考虑以下这个简单的示例程序:
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
|
||||
int num() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void bar(int i) {
|
||||
printf("i = %d\n", i);
|
||||
}
|
||||
|
||||
int main() {
|
||||
bar(num());
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
如果你在没有 <ruby>调试符号<rt> debugging sysbols </rt></ruby> 的情况下进行编译(即在使用 `gcc` 编译程序时上,没有写 `-g` 选项),然后在 `bar` 上设置一个断点,然后尝试在这个函数内使用 `step`,来单步执行语句。GDB 会给出一个 <ruby>没有行号信息<rt> no line number information </rt></ruby> 的错误信息。
|
||||
|
||||
```
|
||||
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` 命令来代替 `step`。`stepi` 一次只执行一条指令。当使用 GDB 的 `stepi` 命令时,先做 `display/i $pc` 通常很有用,这会在每一步之后**显示** <ruby>**程序计数器的值**<rt> program counter value </rt></ruby> 和**相应的** <ruby>**机器指令**<rt> machine instruction </rt></ruby>:
|
||||
|
||||
```
|
||||
(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
|
||||
```
|
||||
|
||||
在上述的 `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 <bar+8>: mov %edi,-0x4(%rbp)
|
||||
```
|
||||
|
||||
### 3、复杂的函数调用
|
||||
|
||||
在带调试符号的 `-g` 选项,重新编译示例程序后,你可以用 `main` 中的行号,在 `bar` 上设置断点,然后再单步执行 `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` 命令,这样就不需要以上的序列了。为了证明这一点,你需要像以前一样将断点设置在 `main` 的 `bar` 调用上。然后在 `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 <none> n num
|
||||
```
|
||||
|
||||
如果不再需要 `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 <none> n num
|
||||
2 y n <none> n bar
|
||||
(gdb) skip delete
|
||||
(gdb) info skip
|
||||
Not skipping any files or functions.
|
||||
```
|
||||
|
||||
### GDB 的 `step` 命令
|
||||
|
||||
使用 GDB 的 `step` 命令是调试程序的一个有用工具。即使是复杂的函数,也有几种方法可以进入这些函数,所以下次你在排除代码问题的时候,可以尝试一下这些 GDB 技术。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/12/gdb-step-command
|
||||
|
||||
作者:[Alexandra][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[chai001125](https://github.com/chai001125)
|
||||
校对:[校对者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