2014-12-12日学习笔记
gdb调试
一、启动dgb
1、源代码编译
操作:GCC要带-g选项,目的是让编译器将符号表(对应于程序的变量和代码行的内存地址列表)保存在生成的可执行文件中。这样才能在调试会话过程中引用源代码中的变量名和行号。
举例:gcc –g –o main main.c
2、启动
启动gdb的方法有以下几种:
(1)gdb + ProgramName
说明:ProgramName 也就是可执行程序文件,一般在当前目录下
举例:gdb main
(2)gdb + ProgramName +core
说明:如果一个程序发生了错误,而且生成了core文件,core文件是程序非法执行后core dump产生的文件。一个程序必须开启core file size后才能生存core文件,用ulimite –a命令可以查看当前可执行程序的core file size。开启core file size的方法:ulimit -c unlimited。
举例:gdb main core
(3)gdb + ProgramName +PID
说明:如果程序是一个服务程序,那么可以通过制定服务程序运行时的PID,gdb会自动的attach上去。
(4) gdb -command=z x
说明:在调用GDB时可以指定启动文件,如:$gdb-command=z x
表示要在可执行文件x上运行GDB,首先要从文件z中读取命令。
gdb启动文件
有时候我们在完成调试前可能需要退出GDB,比如需要离开比较长的一段时间而且不能保持登录在计算机中。为了不丢失某些信息,可以将断点和设置的其他命令放在一个GDB启动文件中,然后每次启动GDB时会自动加载它们。
GDB启动文件默认名为.gdbinit。可以将一个文件放在主目录中用于一般用途,另一个文件放在特定项目专用的目录中。例如,可以将设置断点的命令放在后一个目录的启动文件中,在主目录的.gdbinit文件中存储开发的一些通用的宏。最好不要将编程项目放在主目录中,因为不能将项目特有的信息放在.gdbinit中。
带参数的可执行程序
如果可执行程序带有参数,可在启动gdb后,set args + 参数,就可设定程序运行时需要的参数,show paths 查看程序的运行路径。
3、以TUI模式运行GDB
在调用gdb的时候指定-tui选项或者在处于非TUI模式时在GDB中使用Ctrl+X+A组合键,可以将终端屏幕分成原文本窗口和控制台的多个子窗口
二、查看代码
list命令可用于显示指定位置处的源代码。list命令会影响当前行和当前文件。list命令有多种方式指定要显示的源代码范围,可以是行号,函数名,甚至是指令地址。常用的如下:
list linenum:显示指定行数附近的代码。
list function:显示指定函数附近的代码。
list + 列出当前行的后面代码行。
list - 列出当前行的前面代码行。
list *addr:显示指定地址附近的代码。
默认情况下,GDB显示指定位置处以及其前后的10行代码,但是这是一个可设置的值。
set listsize count:设置list命令显示的源代码数量最多为count行,0表示不限制行数。
show listsize:显示listsize的值。
三、断点设置
1、设置断点
(1)break line_number:在某一行设置断点。
(2)break function(函数名):在某个函数的入口(第一行可执行代码)处设置断点。
(3)break filename:function:在源代码文件filename的函数function入口处处设置断点。
(4)conditionbreak_p_num(断点编号) cond(条件):将正常断点转变为条件断点
举例:condition 30 index == 5
(5)break line_num(行号) if cond(条件):用break if可以将break和condition命令组合成一个步骤:举例:(gdb) break 30 if index == 5
2、查看断点
info break:显示所有断点信息
3、删除断点:
(1)deletebreak_point_num:删除编号为break_point_num的断点;
(2)delete:删除所有断点;
(3)clear function:删除在function函数处设定的断点
(4)clearfilename:funtion删除在filename文件的function函数处设定的断点
(5)clear line_number:删除在line_number行设定的断点
(6)clearfilename:line_number:删除在filename文件的line_number行设定的断点
4、禁用与启用断点
(1)disablebreakpoint-list(是用空格分隔开的多个断点标识符):禁用断点
(2)disable:禁用所有现存断点
(3)enablebreakpoint-list:启用断点
(4)enable oncebreakpoint-list:在下次引起GDB暂停执行后禁用
5、断点命令列表
让GDB在每次到达某个断点时自动执行一组命令,从而自动完成某一任务。
使用commands命令设置命令列表:
commands breakpoint_number
...
commands
...
end
例如以下代码:
我打算查看传递给fibonacci函数的值以及次序,但是不想在程序中插入printf语句并重新编译代码,可以这样做:
在该函数入口处设置一个断点,然后设置命令列表:
printf命令和C中printf函数类似,只是括号是可选的。
运行结果:
如果嫌GDB输出太冗长,可以使用silent命令,只需将其添加到设置的命令列表最开始处即可。
四、调试
1、启动:run
2、查看栈帧:frame num(栈帧编号)
注意栈帧编号规则,当前正在执行的函数的帧被编号为0,其父帧(即该函数的调用者的栈帧)被编号为1,父帧的父帧被编号为2,以此类推。
跳到调用栈中的下一个父帧:up
引向相反方向:down
显示整个栈,即当前存在的所有帧的集合:backtrace
3、输出当前值:print或者p
4、浏览以前的GDB命令:上一个Ctrl+P、下一个Ctrl+N
5、可以直接按下回车再次执行最近执行过的那条命令
6、运行
(1)单步执行:step(s)、next(n),仅执行到代码的下一行后再次暂停。
注意二者区别:在函数调用时step会进入函数,next导致下一次暂停出现在调用函数之后。next被称为单步越过(stepping over)函数,而step被称为单步进入(stepping into)函数。
next和step都可以采用一个可选的数值参数,来表示要使用next或step执行的额外行数。
(2)无条件恢复程序的执行:continue(c)
直到遇到另一个断点或者程序结束。
continue可以接受一个可选的数值参数n,要求GDB忽略下面n个断点。
(3)用finish(fin)或until(u)命令恢复。
finish命令指示GDB恢复执行,直到恰好在当前帧完成之后为止。
until命令通常用来在不进一步在循环中暂停(除了循环中的中间断点)的情况下完成正在执行的循环。until会执行循环的其余部分(如果遇到断点,还是会暂停),让GDB在循环后面的第一行代码处暂停。
until命令也可以接受源代码中的位置作为参数,其用法与break命令同。
比如下列代码清单swapflaw.c:
如果GDB触发了main函数入口处的一个断点,那么可以使用下面这些命令方便地使程序一直执行到swap()的入口:
until 13
until swap
until swapflaw.c:13
until swapflaw.c:swap
7、退出:quit