在 Linux 中如何使用 gdb 调试 C 程序
gcc gdb
无论多么有经验的程序员，开发的任何软件都不可能完全没有 bug。因此，排查及修复 bug 成为软件开发周期中最重要的任务之一。有许多办法可以排查 bug（测试、代码自审等等），但是还有一些专用软件（称为调试器）可以帮助准确定位问题的所在，以便进行修复。


如果你是 C/C++ 程序员，或者使用 Fortran 和 Modula-2 编程语言开发软件，那么你将会很乐意知道有这么一款优秀的调试器 - [GDB](https://www.sourceware.org/gdb/) - 可以帮你更轻松地调试代码 bug 以及其它问题。在这篇文章中，我们将讨论一下 GDB 调试器的基础知识，包括它提供的一些有用的功能/选项。


![](/data/attachment/album/201702/04/175653ff8gl0f5flw4f518.jpg)


在我们开始之前，值得一提的是，文章中的所有说明和示例都已经在 Ubuntu 14.04 LTS 中测试过。教程中的示例代码都是 C 语言写的；使用的 shell 为 bash（4.3.11）；GDB 版本为 7.7.1。


### GDB 调试器基础


通俗的讲，GDB 可以让你看到程序在执行过程时的内部流程，并帮你明确问题的所在。我们将在下一节通过一个有效的示例来讨论 GDB 调试器的用法，但在此之前，我们先来探讨一些之后对你有帮助的基本要点。


首先，为了能够顺利使用类似 GDB 这样的调试器，你必须以指定的方式编译程序，让编译器产生调试器所需的调试信息。例如，在使用 gcc 编译器（我们将在本教程之后的章节用它来编译 C 程序示例）编译代码的时候，你需要使用 `-g` 命令行选项。


想要了解 gcc 编译器手册页中关于 `-g` 命令行选项相关的内容，请看[这里](https://linux.die.net/man/1/gcc)。


下一步，确保在你的系统中已经安装 GDB 调试器。如果没有安装，而且你使用的是基于 Debian 的系统（如 Ubuntu），那么你就可以使用以下命令轻松安装该工具：



```
sudo apt-get install gdb

```

在其他发行版上的安装方法，请看[这里](https://www.sourceware.org/gdb/download/)。


现在，当你按照上述的方式编译完程序（gcc `-g` 命令行选项），同时也已经安装好 GDB 调试器，那么你就可以使用以下命令让程序在调试模式中运行：



```
gdb [可执行程序的名称]

```

这样做会初始化 GDB 调试器，但你的可执行程序此时还不会被启动。在这个时候你就可以定义调试相关的设置。例如，你可以在特定行或函数中设置一个断点让 GDB 在该行暂停程序的执行。


接着，为了启动你的程序，你必须输入执行以下 gdb 命令：



```
run

```

在这里，值得一提的是，如果你的程序需要一些命令行参数，那么你可以在这里指定这些参数。例如：



```
run [参数]

```

GDB 提供了很多有用的命令，在调试的时候总是能派的上用场。我们将在下一节讨论其中一部分命令。


### GDB 调试器用例


现在我们对 GDB 及其用法有了基本的概念。因此，让我们举例来应用所学的知识。这是一段示例代码：



```
#include <stdio.h>

int main()
{
    int out = 0, tot = 0, cnt = 0;
    int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};

    while(cnt < 10)
    {
        out = val[cnt];
        tot = tot + 0xffffffff/out;
        cnt++;
    }

    printf("\n Total = [%d]\n", tot);
    return 0;
}

```

简单说明一下这段代码要做什么事。获取 `val` 数组中每一个值，将其赋值给 `out` 变量，然后将 `tot` 之前的值与 `0xffffffff/out` 的结果值累加，赋值给 `tot` 变量。


这里遇到的问题是，当执行这段代码编译后的可执行程序时，产生以下错误：



```
$ ./gdb-test
Floating point exception (core dumped)

```

因此，要调试这段代码，第一步是使用 `-g` 选项编译程序。命令如下：



```
gcc -g -Wall gdb-test.c -o gdb-test

```

接着，让我们运行 GDB 调试器并指定要调试的可执行程序。命令如下：



```
gdb ./gdb-test

```

现在，我刚才得到的错误是 `Floating point exception`，大部分人可能已经知道，这是因为 `n % x`，当 x 为 0 时导致的错误。所以，考虑到这一点，我在 11 行代码除法运算的位置处添加了一个断点。如下：



```
(gdb)&;break 11

```

注意 `(gdb)` 是调试器的提示信息，我只输入了 `break 11` 命令。


现在，让 GDB 开始运行程序：



```
run

```

当断点第一次被命中时，GDB 显示如下输出：



```
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)

```

正如你所看到的那样，调试器会显示断点所在的行代码。现在，让我们打印出此时 `out` 的值。如下：



```
(gdb) print out
$1 = 5
(gdb)

```

如上所示，值 `5` 被打印出来了。这个时候一切都还是正常的。让调试器继续执行程序直到命中下一个断点，可以通过使用 `c` 命令来完成：



```
c
```

重复上述操作，直到 `out` 值变为 `0` 时。



```
...
...
...
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$2 = 99
(gdb) c
Continuing.

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$3 = 0
(gdb)

```

现在，为了进一步确认问题，我使用 GDB 的 `s`（或 `step`） 命令代替 `c` 命令。因为，我只想让当前程序在第 11 行之后暂停，再一步步执行，看看这个时候是否会发生崩溃。


以下是执行之后输出信息：



```
(gdb) s

Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;

```

是的，如上输出的第一行内容所示，这就是抛出异常的地方。当我再次尝试运行 `s` 命令时，问题最终也得到了确认：



```
(gdb) s

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.

```

通过这种方式，你就可以使用 GDB 调试你的程序。


### 总结


GDB 提供了很多功能供用户研究和使用，在这里，我们仅仅只介绍了很少一部分内容。通过 GDB 的手册页可以进一步了解这个工具，当你在调试代码的时候，尝试使用一下它。GDB 调试器有一定的学习难度，但是它很值得你下功夫学习。




---


via: <https://www.howtoforge.com/tutorial/how-to-debug-c-programs-in-linux-using-gdb/>


作者：[Ansh](https://www.howtoforge.com/tutorial/how-to-debug-c-programs-in-linux-using-gdb/) 译者：[zhb127](https://github.com/zhb127) 校对：[jasminepeng](https://github.com/jasminepeng)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
# How to Debug C Programs in Linux using gdb

### On this page

No matter how experienced you are as a programmer, any software you develop cannot be completely free of bugs. That's why identifying bugs and fixing them is one of the most important tasks in the software development cycle. While there are many ways to find bugs (testing, self-checking code, etc.), there is also special software - called debuggers - that helps you understand exactly where the problem is so you can easily fix it.

Assuming you are a C/C++ programmer or develop software using the Fortran and Modula-2 programming languages, in this case you will be glad to know that there is an excellent debugger - called GDB - that you can use to easily check your code for errors and other problems. In this article we will discuss the basics of GDB and some of its useful features/options.

## GDB debugger basics

In layman's terms, GDB lets you peek inside a program while the program is executing, something that lets you help identify where exactly the problem is. We'll discuss the usage of the GDB debugger through a working example in the next section, but before that, here, we'll discuss a few basic points that'll help you later on.

Firstly, to successfully use debuggers like GDB, you have to compile your program so that the compiler also produces debugging information that debuggers require. For example, in case of the gcc compiler, which we'll be using to compile the example C program later in this tutorial, you need to use the *-g* command line option while compiling your code.

To know what the gcc compiler's manual page says about this command line option, head [here](https://linux.die.net/man/1/gcc).

Next step is to make sure that you have GDB installed on your system. If that's not the case, and you're on a Debian-based system like Ubuntu, you can easily install the tool using the following command:

sudo apt install gdb

For installation on any other distro, head [here](https://www.sourceware.org/gdb/download/).

Now, once you've compiled your program in a way that it's debugging-ready, and GDB is there on your system, you can execute your program in debugging mode using the following command:

gdb [prog-executable-name]

While this will initiate the GDB debugger, your program executable won't be launched at this point. This is the time when you can define your debugging-related settings. For example, you can define a breakpoint that tells GDB to pause the program execution at a particular line number or function.

Moving on, to launch your program, you'll have to execute the following gdb command:

run

It's worth mentioning that if your program requires some command line arguments to be passed, you can specify them here. For example:

run [arguments]

GDB provides many useful commands that come in handy while debugging. We'll discuss some of them in the example in next section.

## GDB usage example

Now we have a basic idea about GDB as well as its usage. So let's take an example and apply the knowledge there. Here's an example code:

#include <stdio.h>

int main()

{

int out = 0, tot = 0, cnt = 0;

int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};

while(cnt < 10)

{

out = val[cnt];

tot = tot + 0xffffffff/out;

cnt++;

}

printf("\n Total = [%d]\n", tot);

return 0;

}

So basically, what this code does is, it picks each value contained in the 'val' array, assigns it to the 'out' integer, and then calculates 'tot' by summing up the variable's previous value and the result of '0xffffffff/out.'

The problem here is that when the code is run, it produces the following error:

$ ./gdb-test

Floating point exception (core dumped)

So, to debug the code, the first step would be to compile the program with -g. Here's the command:

gcc -g -Wall gdb-test.c -o gdb-test

Next up, let's run GDB and let it know which executable we want to debug. Here's the command for that:

gdb ./gdb-test

Now, the error I am getting is 'floating point exception,' and as most of you might already know, it's caused by n % x, when x is 0. So, with that in mind, I put a break point at line number 11, where the division is taking place. This was done in the following way:

(gdb)break 11

Note that '(gdb)' is the debugger's prompt. I just wrote the 'break' command.

Now, I asked GDB to start the execution of the program:

run

So, when the breakpoint was hit for the first time, here's what GDB showed in the output:

Breakpoint 1, main () at gdb-test.c:11

11 tot = tot + 0xffffffff/out;

(gdb)

As you can see in the output above, the debugger showed the line where the breakpoint was put. Now, let's print the current value of 'out.' This can be done in the following way:

(gdb)print out$1 = 5

(gdb)

As you can see that the value '5' was printed. So, things are fine at the moment. I asked the debugger to continue the execution of the program until the next breakpoint, something which can be done using the 'c' command.

c

I kept on doing this work, until I saw that the value of 'out' was zero.

...

...

...

Breakpoint 1, main () at gdb-test.c:11

11 tot = tot + 0xffffffff/out;

(gdb) print out

$2 = 99

(gdb) c

Continuing.

Breakpoint 1, main () at gdb-test.c:11

11 tot = tot + 0xffffffff/out;

(gdb)print out$3 = 0

(gdb)

Now, to confirm this is the exact problem, I used GDB's 's' (or 'step') command instead of 'c' this time. I just wanted line 11, where the program execution currently stands paused, to execute, and see if crash occurs at this point.

Here's what happened:

(gdb) sProgram received signal SIGFPE, Arithmetic exception.

0x080484aa in main () at gdb-test.c:11

11 tot = tot + 0xffffffff/out;

Yes, as confirmed by the highlighted output above, this is where the exception was thrown. The final confirmation came when I tried running the 's' command once again:

(gdb) s

Program terminated with signal SIGFPE, Arithmetic exception.

The program no longer exists.

So this way, you can debug your programs using GDB.

## Conclusion

We've just scratched the surface here, as GDB offers many features for users to explore and use. Go through the man page of GDB to learn more about the tool, and try using it whenever you're debugging something in your code. The debugger has a bit of a learning curve, but it's worth the hard work.