📜  GDB-快速指南

📅  最后修改于: 2020-10-16 02:19:07             🧑  作者: Mango


什么是GNU调试器?

调试器是运行其他程序的程序,允许用户对这些程序进行控制,并在出现问题时检查变量。

GNU调试器,也称为gdb,是用于UNIX系统调试C和C++程序的最流行的调试器。

GNU调试器可帮助您获取有关以下内容的信息:

  • 如果发生核心转储,那么程序崩溃在什么语句或表达式上?

  • 如果在执行函数时发生错误,程序的哪一行包含对该函数的调用,以及参数是什么?

  • 在程序执行过程中的某个特定时刻,程序变量的值是多少?

  • 程序中特定表达式的结果是什么?

GDB如何调试?

GDB允许您将程序运行到某个特定点,然后停止并在该点打印某些变量的值,或者一次在程序中单行浏览,并在执行每一行后打印出每个变量的值。

GDB使用简单的命令行界面。

注意事项

  • 尽管GDB可以帮助您找出与内存泄漏有关的bug,但是它不是检测内存泄漏的工具。

  • GDB不能用于编译有错误的程序,也无助于修复这些错误。

GDB-安装

在进行安装之前,请通过发出以下命令检查Unix系统上是否已安装gdb:

$gdb -help 

如果已安装GDB,则它将显示GDB中的所有可用选项。如果未安装GDB,则进行全新安装。

您可以按照以下简单步骤在系统上安装GDB。

步骤1:确保您具有安装gdb的先决条件:

  • 符合ANSI标准的C编译器(建议使用gcc-请注意,gdb可以调试其他编译器生成的代码)

  • 在要构建gdb的分区上需要115 MB的可用磁盘空间。

  • 要安装gdb的分区上需要20 MB的可用磁盘空间。

  • GNU的解压缩程序gzip

  • make实用程序-GNU版本可以正常工作,其他人也可以。

步骤2:ftp.gnu.org/gnu/gdb下载gdb源分发 (这些说明使用了gdb-6.6.tar.gz 。)将分发文件放置在构建目录中。

步骤3:在构建目录中,解压缩gdb-6.6.tar.gz并从存档中提取源文件。文件提取完成后,将工作目录更改为在构建目录中自动创建的gdb-6.6目录。

$ build> gzip -d gdb-6.6.tar.gz 
$ build> tar xfv gdb-6.6.tar 
$ build> cd gdb-6.6 

步骤4:运行configure脚本为您的平台配置源树。

$ gdb-6.6> .⁄configure 

步骤5:使用make实用程序构建gdb。

$ gdb-6.6> make 

步骤6:以root身份登录并使用以下命令安装gdb。

$ gdb-6.6> make install 

步骤7:如果需要,可以在安装完成后通过删除gdb构建目录和存档文件来回收磁盘空间。

$ gdb-6.6> cd .. 
$ build> rm -r gdb-6.6 
$ build> rm gdb-6.6.tar 

现在,您已在系统上安装了gdb并可以使用了。

GDB-调试符号

调试符号表将已编译的二进制程序中的指令映射到源代码中其对应的变量,函数或行。此映射可能类似于:

  • 程序指令⇒项目名称,项目类型,原始文件,行号已定义。

符号表可以嵌入到程序中或存储为单独的文件。因此,如果您打算调试程序,则需要创建一个符号表,该表将具有调试程序所需的信息。

我们可以推断出有关符号表的以下事实:

  • 符号表适用于该程序的特定版本-如果程序更改,则必须创建一个新表。

  • 调试版本通常比零售(非调试)版本更大,更慢。调试版本包含符号表和其他辅助信息。

  • 如果要调试二进制程序而不编译自己,则必须从作者那里获取符号表。

为了使GDB能够从符号表中逐行读取所有信息,我们需要对其进行一些不同的编译。通常,我们将程序编译为:

gcc hello.cc -o hello 

而不是这样做,我们需要使用-g标志进行编译,如下所示:

gcc -g hello.cc -o hello 

GDB-命令

GDB提供了大量命令,但是以下命令是最常用的命令:

  • b main-在程序的开头放置一个断点

  • b-在当前行放置一个断点

  • b N-在第N行放置一个断点

  • b + N-将断点从当前行向下放置N行

  • b fn-在函数“ fn”的开头放置一个断点

  • d N-删除断点编号N

  • 信息中断-列出断点

  • r-运行程序直到断点或错误

  • c-继续运行程序,直到下一个断点或错误

  • f-运行直到当前函数完成

  • s-运行程序的下一行

  • s N-运行程序的后N行

  • n-与s相似,但不进入功能

  • u N-运行直到您在当前行的前面得到N行

  • p var-打印变量“ var”的当前值

  • bt-打印堆栈跟踪

  • u-在堆栈中上移

  • d-降低堆栈中的某个级别

  • q-退出gdb

GDB-调试程序

入门:开始和停止

  • gcc -g myprogram.c

    • 使用调试选项(-g)编译myprogram.c。您仍然会看到a.out,但是它包含调试信息,可让您在GDB中使用变量和函数名,而不是原始内存位置(不好玩)。

  • gdb a.out

    • 使用文件a.out打开GDB,但不运行该程序。您会看到一个提示(gdb)-所有示例均来自此提示。

  • [R

  • r arg1 arg2

  • r <文件1

    • 先前加载的三种运行“ a.out”的方式。您可以直接运行(r),传递参数(r arg1 arg2)或输入文件。通常,您将在运行之前设置断点。

  • 帮帮我

  • h个断点

    • 列出帮助主题(帮助)或获得有关特定主题的帮助(h断点)。 GDB有据可查。

  • q-退出GDB

单步执行代码

通过步进,您可以跟踪程序的路径,并在崩溃或返回无效输入的代码中归零。

  • 50

  • 功能

    • 列出当前行(l),特定行(l 50)或函数(l myfunction)的10行源代码。

  • 下一个

    • 运行程序直到下一行,然后暂停。如果当前行是一个函数,它将执行整个函数,然后暂停。下一步非常适合快速浏览您的代码。

    • 运行下一条指令,而不是行。如果当前指令正在设置变量,则与next相同。如果是一个函数,它将跳入该函数,执行第一条语句,然后暂停。这一步很适合深入您的代码细节。

    • 完成执行当前函数,然后暂停(也称为单步执行)。如果您不小心踏入函数很有用。

断点或观察点

断点在调试中起着重要作用。当程序到达某个点时,他们会暂停(中断)程序。您可以检查和更改变量并恢复执行。当发生某些输入故障或要测试输入时,这很有用。

  • 打破45

  • 破坏我的功能

    • 在第45行或myfunction处设置断点。程序到达断点时将暂停。
  • 看x == 3

    • 设置观察点,当条件发生变化时(x == 3发生变化时),该监视点将暂停程序。监视点非常适合某些输入(myPtr!= NULL),而不必在每次函数调用时中断。

  • 继续

    • 在被断点/监视点暂停后继续执行。程序将继续直到到达下一个断点/观察点。

  • 删除N

    • 删除断点N(创建时对断点编号)。

设置变量

在运行时查看和更改变量是调试的关键部分。尝试为函数提供无效的输入或运行其他测试用例以查找问题的根本原因。通常,您将在程序暂停时查看/设置变量。

  • 打印x

    • 打印变量x的当前值。能够使用原始变量名的原因是需要(-g)标志的原因;定期编译的程序将删除此信息。

  • 设置x = 3

  • 设置x = y

    • 将x设置为设置值(3)或另一个变量(y)
  • 调用myfunction()

  • 调用myotherfunction(x)

  • 呼叫strlen(mystring)

    • 调用用户定义的或系统函数。这是非常有用的,但是要注意调用错误的函数。

  • 显示x

    • 不断显示变量x的值,该变量在每步或暂停后显示。如果您经常检查某个值,则很有用。

  • 取消显示x

    • 删除由display命令显示的变量的常量显示。

回溯和更改框架

堆栈是当前函数调用的列表-它显示您在程序中的位置。框架存储单个函数调用的详细信息,例如参数。

  • bt

    • 回溯或打印当前函数堆栈以显示您在当前程序中的位置。如果主调用函数a()调用b()并调用c(),则回溯为

c <= current location 
b 
a 
main 
  • 向上

    • 在函数堆栈中上移或下移到下一帧。如果您在c中,则可以移至ba来检查局部变量。

  • 返回

    • 从当前函数返回。
  • 处理信号

    信号是在某些事件(例如计时器或错误)之后引发的消息。 GDB遇到信号时可能会暂停;您可能希望忽略它们。

    • 处理[信号名] [操作]

    • 处理SIGUSR1不停

    • 处理SIGUSR1 noprint

    • 处理SIGUSR1忽略

      • 指示GDB在发生特定信号(SIGUSR1)时忽略它。有不同程度的忽略。

    GDB-调试示例

    通过以下示例了解调试程序和转储的核心的过程。

    • 调试示例1

      此示例演示如何捕获由于除零而引发的异常而发生的错误。

    • 调试示例2

      此示例演示了由于未初始化的内存而可以转储内核的程序。

    这两个程序都是用C++编写的,由于不同的原因会生成核心转储。看完这两个示例之后,您应该可以调试生成核心转储的C或C++程序。

    GDB-摘要

    在学习完本教程之后,您必须对使用GNU Debugger调试C或C++程序有一个很好的了解。现在,您应该很容易学习其他调试器的功能,因为它们与GDB非常相似。强烈建议您也通过其他调试器来熟悉它们的功能。

    市场上有很多不错的调试器:

    • DBX调试器-该调试器与Sun Solaris一起提供,您可以使用dbx的手册页(即man dbx)获得有关此调试器的完整信息。

    • DDD Debugger-这是dbx的图形版本,可在Linux上免费使用。要获得完整的详细信息,请使用ddd的手册页,即man ddd

    您可以从以下链接获得有关GNU调试器的全面详细信息:使用GDB进行调试