gdb 软件调试

来源:互联网 发布:算法导论思考题 编辑:程序博客网 时间:2024/04/30 03:16

转自:http://www.findfunaax.com/notes/file/49


一、综述

在《软件调试艺术》这本书的前言里,讲了一个叫Andrew的学生大一时就开始学习了编程,可到大四时还在使用输出调试的方法。 直到他的教授强烈要求他改用正式的调试工具。这怎么和我的情况极其相似呢!-_-!我也是一个'Andrew',也该正式学习学习调试工具了。

在此选用gdb 7.0.1版本,参考书目《软件调试的艺术》。更重要的书是GDB官方手册。

二、快速上手

若调试过程中一眼看不出错误所在,可以设置***监视点***或使用二分搜索原理。

设置断点 -> contine到断点 -> next或step单步调试一段 -> contine到下一断点

调试工具一般有gdb CLI, DDD, eclipse中集成CDT, Emacs中 gdb -tui 打开终端图形化调试或在进入gdb以后输入Ctrl+X+A

重新编译代码时最好不要退出GDB,因为会保留调试时断点等信息。

主目录的.gdbinit文件用于保存gdb的一些宏,在加载可执行文件之前读取; 本地项目的.gdbinit用于保存之前的调试信息,在加载可执行文件之后读取。

'gdb -command=z x'在执行x文件之前读取z文件中的命令

一个为调试的编译过程: gcc -g3 -Wall -Wextra -c main.c swapper.c gcc -o swap main.o swapper.o gdb swap

三、主要调试操作

1. 单步调试源码

断点
'break 行号','info break'查看行号,'break 行号 if 条件'条件暂停
删除断点
'clear 断点号'
单步调试
'next' 执行下一行;执行到函数时会出现在下一次调用函数时;
单步调试
'step' 执行下一行;执行函数时会进入函数;
恢复操作
'continue' 恢复执行并继续,直到遇到断点;
临时断点
'tbreak' 有效期只有首次达到此断点时为止;
设置条件
'condition num 变量条件' num号断点只有在条件成立时才暂停;
函数完毕
'finish' 执行直到当前栈帧完成之后为止;即在函数返回之后停止;
循环完毕
'until' 执行直到到达当前循环体外下一行代码;用于跳过循环,可接收参数

2. 检查变量

输出变量
'print 变量';
监视点
'watch 变量' 当程序变量值改变时gdb暂停,查看程序状态;
表达式监视点
'watch (表达式)', 表达式返回布尔类型值,ex: watch (z > 28);
观察栈帧
'frame 序号', 当前函数栈帧为0,父函数栈帧为1,父帧的父帧为2,以此类推;
移动观察栈帧
'up' 父栈帧, ex:0->1;
移动观察栈帧
'down' 子栈帧, ex:1->0;
显示所有栈帧
'backtrace';

四、GDB调试方法

序号步骤命令备注1编译源代码$gcc -g -Wall -o main program_file.c 2开启gdb工具$gdb main -tui 3从开始处运行程序run若想给程序传入参数,在此输入;再次运行时不必指定参数 挂起Ctrl+C 

五、暂停机制

1. 3种暂停程序方法

以下在帮助文档里可统称为断点:

断点
通知GDB特定位置暂停执行;GDB执行到那一行代码之前;
监视点
通知GDB特定值变化或表达式成立时暂停
捕获点
通知GDB特定事件发生时暂停

2. 跟踪断点

'info breakpoints'列出断点

3.设置断点

命令功能break function在函数入口设置断点(会在所有名为function处设置断点,如c的static函数不同文件可重名,C++的重载函数)break linenumber根据行号设置断点breakfilename:linenumber在源代码文件filename的linenumber处设置断点break filename:function在源代码文件filename的function处设置断点break *address在虚拟内存地址处设置断点(用于源代码不可用或共享库的调试)

注:

  1. 断点的有效性持续到删除、禁用或退出GDB时
  2. 临时断点tbreak有相同的命令设置
  3. hbreak,thbreak等其它断点类型
  4. 修改代码后,GDB自动重载,但断点是根据行号继承上次的

4.删除断点

命令功能delete breakpointlist根据断点号列表删除断点delete删除所有断点clear清除GDB将执行的下一处断点clear function、 filename:function 、 linenumber 、 filename:linenumber同break相似

5.禁用断点

命令功能disable breakpointlist禁用断点enable breakpointlist启用断点enable once breakpointlist启用一次断点

6.GDB断点属性

序号Num属性Type部署Disp启用状态Enb地址Address位置What1..断点Breakpoint
监视点watchpoint
捕获点catchpoint保持Keep
删除del
禁用disy/n0x........断点位置的行号和文件名

7.恢复执行方法

调试的过程是确认程序中某些变量有我们认为该有的值。这就需要暂停去观察。可暂停后还要进行恢复执行。GDB的恢复执行方法有3类。

  1. 使用step和next单步调试,仅执行代码下一行然后再次暂停;
  2. 使用continue使GDB无条件继续执行,直到它遇到一个断点或程序结束;
  3. 使用finish或until有条件继续执行,直到到达某个预先条件、另一断点或程序结束;

8.条件断点

常用于监视变量是否得到错误的值。如果得到,就中断停止。

命令功能break break-args if (condition)condition为布尔表达式,'('号可选cond N condition转换无条件的中断为有条件的condition 包括:相等、逻辑和不相等运算符< <= == != > >= && || 等按位和移位运算符& | ^ >> <<算术运算符+ - * / %自己的函数要链接到程序中,ex: 'break test.c:myfunc if ! check_variable_sanity(i)'库函数要链接到程序中,ex: 'break 44 if strlen(mystring) == 0';GDB只认返回值为int

9.断点命令列表

当GDB遇断点停止时,几乎每次都要查看某些变量。因此可以让GDB每次到达某个断点时自动执行一组指令,这就是断点命令列表。 commands breakpoint-number
...
commands
...
end
可以给定一个空commands来取消此命令列表。 可以在命令列表第一行加上silent命令,使GDB安静的触发。 可以用define命令创建宏来方便调用,用show user查看所有宏列表。

六、检查和设置变量

1.查看变量

命令功能x检查给定地址的内存display每次暂停时输出指定条目call调用程序内的函数print *pointer@number_of_elements打印动态数组,使用GDB的人工数组。info locals得到当前栈帧中所有的局部变量列表

2.设置变量

ex: xset x = 12

3.GDB自己的变量

使用值历史
$1,$2..., $
方便变量
临时记录某些节点的值,ex 'set $q = p', q是方便变量,p是程序变量

七、零散

1. GDB给人一种逐行运行源代码的错觉。

2. 变量名就是增强符号表。

3. 在调试完成前永远不应优化代码。(过早优化是万恶之源)

4. 使用cat /proc/进程号/maps来查看进程的内存布局。