调试工具:
gdb
unix程序员最常用的调试工具是gdb,大多数linux系统应该预先安装了gdb。如果没有预先安装该工具,则必须下载gcc编译器程序包。
ddd
随着gui(图形用户界面)越来越流行,大量的unix环境下运行的基于gui的调试器被开发出来。其中的大多数工具都是gdb的gui前端:用户通过gui发出命令,gui将这些命令传递给gdb。ddd就是其中的一种工具。
如果你的系统还没有安装ddd,则可以下载该工具。例如,centos系统上,命令
将自动处理整个安装过程。
主要调试器操作
1 单步调试源代码
可以安排程序的执行run在某个地方暂停,以便检查变量的值,从而得到关于程序错误所在位置的线索。下面是可用来暂停程序执行的一些方法。
断点
正如前面所说,调试工具会在指定断电处暂停程序的执行。在gdb中是通过break命令及其行号完成的,在ddd中是在相关代码行的任意空白处右击并选择set breakpoint来完成的。
单步调试
gdb的next命令让gdb执行下一行,然后暂停。step命令的作用于此类似,只是在函数调用时step命令会进入函数,而next导致程序执行的暂停出现在下次调用函数时。ddd有对应的next和step菜单项。
恢复操作
在gdb中,continue命令通知调试其恢复执行并继续,直到遇到断点为止。ddd中有一个对应的菜单项。
临时断点
在gdb中,tbreak命令和break相似,但是这一命令设置的断电的有效期只到首次到达指定行时为止。在ddd中临时断点的设置方式为:在源文本窗口中要设置断点的代码行的任意空白处右击,然后选择set temporary breakpoint。
gdb中还有创建特殊类型的一次性断点的命令:until和finish。ddd的命令工具中有对应的until和finish项。
程序执行的典型调试模式如下(以gdb为例):单击一个断点后,通过gdb的next命令一次移动一行代码,或通过step命令单步调试一段时间,以便仔细检查靠近断点处的程序状态和行为。做完这些操作后,可以用continue命令让调试器继续执行程序,直到遇到下一个断点为止,其间不需要暂停。
gdb的暂停机制
有3种方式可以通知gdb的暂停程序的执行。
断点:通知gdb在程序中的特定位置暂停执行。
监视点:通知gdb当特定内存位置(或者涉及一个或多个位置的表达式)的值发生变化时暂停执行
捕获点:通知gdb当特定事件发生时暂停执行。
断点概述
断点就像程序中的绊网:在程序中的特定“位置”设置断点,当到达那一点时,调试器会暂停程序的执行(在gdb这样的基于文本的调试器的情况下,会出现命令行提示符)。
gdb中关于“位置”的含义是非常灵活的,它可以指各种源代码行、代码地址、源代码文件中的行号或者函数的入口等。
gdb执行到断点行之前,gdb显示的是将要执行的代码行。
然而,gdb的工作针对的是机器语言指令,而不是源代码行,一行代码可能对应于数行机器语言。
可以使用info breakpoints命令获得断点信息。使用delete + 断点编号来删除断点。
设置断点
在gdb中设置断点
gdb中有许多指定断点的方式,下面是一些最常见的方法。
break function
在函数function()的入口(第一行可执行代码)处设置断点。
(gdb) break main
在main()的入口处设置断点。
break line_number
在当前活动源代码文件的line_number处设置断点。对于多行程序,这要么是上次使用list命令查看其内容的文件,要么是包含main()的文件。
(gdb) break 35
它在文件的第35行处设置了一个断点。
break filename:line_number
在源代码文件filename的line_number处设置断点。如果filename不在当前工作目录中,则可以给出相对路径名或者完全路径名来帮助gdb查找该文件,例如:
(gdb) break source/bed.c:35
break filename:function
在文件filename中的函数function()的入口处设置断点。重载函数或者使用同名静态函数的程序可能需要使用这种方式,例如:
(gdb) break bed.c:parsearguments
正如我们看到的,当设置一个断点时,该断点的有效性会持续到删除、禁用或退出gdb时。然而,临时断点是首次到达后就会自动删除的断点。临时断点使用tbreak命令设置,它与break采用相同类型的参数。例如,tbreak foo.c在文件的第10行设置临时断点。
当同一行源代码上有多个断点时会发生什么情况。当gdb使用多个断点中断一行源代码时,它只会中断一次。换言之,当它到达该行代码时,如果恢复执行,会忽略恰好在同一行的其他断点。事实上,gdb知道是哪个断点“触发”了程序停止执行。在具有多个断点的代码行上,触发中断的断点将是标识符编号最小的断点。
断点的持久性
如果在重新修改编译源代码期间不退出gdb。例如,当发现并修复了一个程序错误,但是其他程序错误仍然存在时,不应当退出gdb然后重新进入来使用程序的新版本。这样做有些不必要地繁琐,而且还会不得不重新进入断点。
如果在修改和重新编译代码时没有退出gdb,那么在下次执行gdb的run命令时,gdb会感知到代码已经修改,并自动重新加载新版本。
删除和禁用断点
如果确认不再需要当前断点,那么可以删除该断点。gdb中有两个用来删除断点的命令。delete命令用来基于标识符删除断点,clear命令使用创建断点相同的语法删除断点。
delete breakpoint_list
删除断点使用数值标识符。断点可以是一个数字,比如delete 2删除第二个断点;也可以是数字列表,比如delete 2 4 删除第二个和第四个断点。
delete
删除所有断点。除非执行也可以放在.gdbinit启动文件中的set confirm off命令,否则gdb会要求确认删除操作。
clear
清除gdb将执行的下一个指令处的断点。这种方法适用于要删除gdb已经到达的断点的情况。
clear function、clear filename:function、clear line_number和clear filename:line_number
这些命令根据位置清楚断点,工作方式与对应的break命令相似。
在gdb中禁用断点
每个断点都可以被启用或禁用。只有当gdb遇到启用的断点时,才会暂停程序的执行;它会忽略禁用的断点。默认情况下,断点的生命期从启用时开始。
使用disable breakppoint-list命令禁用断点,使用enable breakpoint-list命令启用断点,其中breakpoint-list是使用空格分隔的列表,其中有一个或多个断点标识符。例如
(gdb) disble 3
将禁用第三个断点。类似地,
(gdb) enable 1 5
将启用第一个和第五个断点。
不带任何参数地执行disable命令将禁用所有现有断点。类似地,不带参数地执行enable命令会启用所有现有断点。
还有一个enable once命令。在断点下次引起gdb暂停执行后被禁用。语法为:
enable once breakpoint-list