当前位置: 首页 > 科技观察

Linux下如何使用gdb调试C程序

时间:2023-03-12 08:34:54 科技观察

无论是多么有经验的程序员,开发出的软件都不可能完全没有bug。因此,故障排除和修复错误已成为软件开发周期中最重要的任务之一。解决错误的方法有很多种(测试、代码自我审查等),但也有专门的软件(称为调试器)可以帮助查明问题,以便进行修复。如果你是C/C++程序员,或者使用Fortran和Modula-2编程语言开发软件,那么你会很高兴知道有这么好的调试器——GDB——可以帮助你更轻松地调试代码错误和其他问题.在本文中,我们将讨论GDB调试器的基础知识,包括它提供的一些有用的功能/选项。在开始之前,值得一提的是,本文中的所有说明和示例都已在Ubuntu14.04LTS上进行了测试。教程中的示例代码是用C语言编写的;使用的外壳是bash(4.3.11);GDB版本是7.7.1。GDBDebuggerBasics通俗地说,GDB可以让你看到程序在执行过程中的内部过程,帮助你找出问题所在。我们将在下一节中通过一个工作示例讨论GDB调试器的用法,但在此之前,让我们先了解一些基础知识,这些知识稍后会对您有所帮助。首先,为了能够顺利的使用GDB这样的调试器,必须按照指定的方式编译程序,让编译器生成调试器需要的调试信息。例如,当使用gcc编译器(我们将在本教程后面用于编译示例C程序)编译代码时,您需要使用-g命令行选项。要阅读gcc编译器手册页中的-g命令行选项,请参见此处。接下来,确保您的系统上安装了GDB调试器。如果没有安装,而你使用的是基于Debian的系统(如Ubuntu),那么你可以使用以下命令轻松安装该工具:sudoapt-getinstallgdb其他发行版的安装方法请参见此处。现在,当您按上述方式编译了程序(gcc-g命令行选项)并安装了GDB调试器后,您可以使用以下命令在调试模式下运行该程序:gdb[可执行程序的名称]这样做将初始化GDB调试器,但您的可执行文件尚未启动。此时你可以定义调试相关的设置。例如,您可以在特定行或函数设置断点,让GDB在该行暂停程序执行。接下来,为了启动你的程序,你必须输入以下gdb命令:run在这里,值得一提的是,如果你的程序需要一些命令行参数,那么你可以在这里指定这些参数。例如:run[parameter]GDB提供了很多有用的命令,在调试的时候总能派上用场。我们将在下一节中讨论其中的一些命令。GDB调试器用例现在我们对GDB及其用法有了一个基本的了解。因此,让我们通过一个例子来应用我们学到的知识。这是一个示例代码:#includeintmain(){intout=0,tot=0,cnt=0;intval[]={5,54,76,91,35,27,45,15,99,0};while(cnt<10){out=val[cnt];tot=tot+0xffffffff/out;cnt++;}printf("\nTotal=[%d]\n",tot);return0;}简单解释一下这段代码要做什么做。获取val数组中的每一个值,赋给out变量,然后将tot的前一个值和0xffffffff/out的结果值相加,赋给tot变量。这里遇到的问题是,在执行这段代码编译后的可执行程序时,会产生如下错误:$./gdb-testFloatingpointexception(coredumped)因此,要调试这段代码,第一步是使用-g选项编译程序。命令如下:gcc-g-Wallgdb-test.c-ogdb-test接下来,让我们运行GDB调试器并指定要调试的可执行文件。命令如下:gdb./gdb-test现在,我刚刚得到的错误是一个浮点异常,你们中的大多数人可能已经知道,它是由n%x当x为0时引起的。所以,记住这一点,我在除法运算发生的第11行添加了一个断点。如下:(gdb)&;break11注意,(gdb)是调试器的提示信息,我只输入了break11命令。现在,让GDB开始运行程序:run当第一次命中断点时,GDB显示以下输出:Breakpoint1,main()atgdb-test.c:1111tot=tot+0xffffffff/out;(gdb)asAs可以看到,调试器会显示断点所在的代码行。现在,让我们打印出此时out的值。如下:(gdb)printout$1=5(gdb)如上所示,打印出数值5。此时一切正常。让调试器继续执行程序,直到下一个断点,这可以使用c命令来完成:c重复上述操作,直到out值变为0。......Breakpoint1,main()atgdb-test。c:1111tot=tot+0xffffffff/out;(gdb)printout$2=99(gdb)cContinuing.Breakpoint1,main()atgdb-test.c:1111tot=tot+0xffffffff/out;(gdb)printout$3=0(gdb)现在,为了进一步确认问题,我使用了GDB的s(或step)命令,而不是c命令。因为,我只是想让当前程序在第11行之后暂停一下,一步步执行,看看此时会不会crash。下面是执行后的输出信息:(gdb)sProgramreceivedsignalSIGFPE,Arithmeticexception.0x080484aainmain()atgdb-test.c:1111tot=tot+0xffffffff/out;是的,如上面输出的第一行所示,这是抛出异常的地方。当我再次尝试运行s命令时,终于确认了问题:(gdb)sProgramterminatedwithsignalSIGFPE,Arithmeticexception.Theprogramnolongerexists。这样,您就可以使用GDB调试您的程序。总结GDB提供了很多功能供用户研究和使用,这里我们只介绍其中的一小部分内容。通过GDB手册页阅读有关此工具的更多信息,并在调试代码时尝试一下。GDB调试器学习起来有些困难,但值得付出努力。