Linux gdb 命令实战示例

LinuxLinuxBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在本实验中,我们将介绍 GNU 调试器(gdb)并探索其在调试 C 程序中的使用。gdb 是一个强大的工具,允许你检查运行中的程序状态、设置断点,并逐步执行代码以识别和修复问题。我们将首先确保在 Ubuntu 22.04 Docker 容器中安装了 gdb,然后创建一个带有运行时错误的简单 C 程序,并使用 gdb 进行调试。最后,我们将演示如何使用 gdb 调试多线程 C 程序。

Linux 命令速查表

gdb 介绍及其使用

在本步骤中,我们将介绍 GNU 调试器(gdb)并探索其在调试 C 程序中的使用。gdb 是一个强大的工具,允许你检查运行中的程序状态、设置断点,并逐步执行代码以识别和修复问题。

首先,确保在我们的 Ubuntu 22.04 Docker 容器中安装了 gdb:

sudo apt-get update
sudo apt-get install -y gdb

示例输出:

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libasan6 libubsan1 python3-gdb
Suggested packages:
  gdb-multiarch
The following NEW packages will be installed:
  gdb libasan6 libubsan1 python3-gdb
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 3,470 kB of archives.
After this operation, 13.5 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

接下来,我们创建一个简单的 C 程序用于调试。在 ~/project 目录下创建一个名为 example.c 的文件,内容如下:

#include <stdio.h>

int main() {
    int a = 5;
    int b = 0;
    int c = a / b;
    printf("The result is: %d\n", c);
    return 0;
}

这个程序会故意除以零,从而引发运行时错误。

要使用 gdb 调试此程序,请按照以下步骤操作:

  1. 使用 -g 标志编译程序以包含调试符号:
gcc -g -o example example.c
  1. 启动 gdb 调试器并加载编译后的程序:
gdb ./example
  1. 在 gdb 提示符中,在 main 函数处设置断点:
(gdb) break main
Breakpoint 1 at 0x11a6: file example.c, line 4.
  1. 运行程序:
(gdb) run
Starting program: /home/labex/project/example
  1. 当程序命中断点时,你可以检查变量、逐步执行代码并调试问题:
Breakpoint 1, main () at example.c:4
4       int a = 5;
(gdb) print a
$1 = 5
(gdb) next
5       int b = 0;
(gdb) print b
$2 = 0
(gdb) next
6       int c = a / b;

如你所见,当程序尝试除以零时,会触发一个运行时错误,可以通过 gdb 捕获并调试该错误。

使用 gdb 调试一个简单的 C 程序

在本步骤中,我们将使用 gdb 调试一个包含运行时错误的简单 C 程序。

首先,在 ~/project 目录下创建一个名为 simple.c 的新 C 文件,内容如下:

#include <stdio.h>

int main() {
    int x = 10;
    int y = 0;
    int z = x / y;
    printf("The result is: %d\n", z);
    return 0;
}

这个程序会故意除以零,从而引发运行时错误。

接下来,使用 -g 标志编译程序以包含调试符号:

gcc -g -o simple simple.c

然后,启动 gdb 调试器并加载编译后的程序:

gdb ./simple

在 gdb 提示符中,在 main 函数处设置断点:

(gdb) break main
Breakpoint 1 at 0x11a6: file simple.c, line 4.

现在,运行程序:

(gdb) run
Starting program: /home/labex/project/simple

当程序命中断点时,你可以检查变量、逐步执行代码并调试问题:

Breakpoint 1, main () at simple.c:4
4       int x = 10;
(gdb) print x
$1 = 10
(gdb) next
5       int y = 0;
(gdb) print y
$2 = 0
(gdb) next
6       int z = x / y;

如你所见,当程序尝试除以零时,会触发一个运行时错误,可以通过 gdb 捕获并调试该错误。

使用 gdb 调试多线程 C 程序

在本步骤中,我们将使用 gdb 调试一个存在竞态条件(race condition)的多线程 C 程序。

首先,在 ~/project 目录下创建一个名为 multithreaded.c 的新 C 文件,内容如下:

#include <stdio.h>
#include <pthread.h>

int shared_variable = 0;

void* thread_function(void* arg) {
    for (int i = 0; i < 1000000; i++) {
        shared_variable++;
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, thread_function, NULL);
    pthread_create(&thread2, NULL, thread_function, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Final value of shared_variable: %d\n", shared_variable);
    return 0;
}

该程序创建了两个线程,每个线程都会对共享变量 shared_variable 递增 1,000,000 次。由于竞态条件的存在,共享变量的最终值可能不会达到预期的 2,000,000。

接下来,使用 -g 标志编译程序以包含调试符号:

gcc -g -o multithreaded multithreaded.c -lpthread

然后,启动 gdb 调试器并加载编译后的程序:

gdb ./multithreaded

在 gdb 提示符中,在 thread_function 函数的开头设置断点:

(gdb) break thread_function
Breakpoint 1 at 0x11b6: file multithreaded.c, line 7.

现在,运行程序:

(gdb) run
Starting program: /home/labex/project/multithreaded

当程序命中断点时,你可以检查变量、逐步执行代码并调试竞态条件:

Breakpoint 1, thread_function (arg=0x0) at multithreaded.c:7
7       for (int i = 0; i < 1000000; i++) {
(gdb) print shared_variable
$1 = 0
(gdb) step
8           shared_variable++;
(gdb) print shared_variable
$2 = 1

通过逐步执行代码并检查共享变量,你可以观察到竞态条件,并识别多线程程序中的问题。

总结

在本实验中,我们介绍了 GNU 调试器(gdb)并探索了其在调试 C 程序中的使用。我们首先确保在 Ubuntu 22.04 Docker 容器中安装了 gdb,然后创建了一个带有运行时错误的简单 C 程序进行调试。我们使用 -g 标志编译程序以包含调试符号,启动 gdb 调试器,在 main 函数处设置断点,并运行程序。当程序命中断点时,我们能够检查变量、逐步执行代码并调试问题。

本实验涵盖了使用 gdb 调试简单 C 程序的基础知识,以及调试多线程 C 程序的内容。通过遵循逐步说明,学习者获得了使用这一强大调试工具的实践经验。

Linux 命令速查表