GDB调试说明
---- SeaSon from DB-LAB of HIT
安装篇
下面介绍的方法是以在cygwin中安装gdb为例说明。
1. 重新运行cygwin的setup文件,选择界面中的keep(必须!!!否则会死的很惨的),从列表中选择gdb组件,然后选择安装即可。
2. 修改Makefile,添加调试信息
修改Makefile(注意:修改的是没有任何后缀的文件,不是Makefile.vc或者Makefile.in)
在下面位置添加-g
CCOPT = -g //这后面可能还有其他参数,保留即可
3. 接着需要重新编译NS2
进入ns-2.2* 目录下面执行
make clean
接着make depend # 执行这个命令过程中如出错,不用管!
然后make
如果上面过程中没有错误,则恭喜你安装成功:)
如果要使用图形界面,则安装过程中需要安装tcltk库,然后对于2003(以前的有些版本页可以)以后的默认都回安装图形界面调试工具insight。后面的说明都是基于命令行界面的,适用比较稳定、方便。
常用命令
1. 进入gdb调试状态,在Cygwin窗口或者Xwin窗口输入命令gdb ns,如下图所示:
2.设置断点
命令格式
b设置端点命令
https://www.wendangku.net/doc/fd7143564.html, 调试的文件,Ns2中任何一个C++文件都可以进行调试
“:”行数指示符
112为行号
当然设置断点的格式还有其他,具体参见手册。
3. 删除断点
命令格式:
其中d为delete
b为breakpoints
2为断点的编号
利用2.中的方法继续创建断点2、3。
利用命令d b 1即删除第一个断点(Breakpoint 1 at 0x4e0a9d: file aodv/https://www.wendangku.net/doc/fd7143564.html,, line 112.),如下图所示
4.运行脚本
命令格式:r scrip.tcl
其中r为命令
scrip.tcl为脚本
以ns自带的wireless1.tcl为例,我们首先在https://www.wendangku.net/doc/fd7143564.html,的recv函数开始设置端点如下图所示:
运行测试脚本wireless.tcl,如下图所示:
然后程序在断点位置停止,如下图所示:
5. 显示变量或函数值
命令格式:display var
其中var可以为变量名或者函数名
在recv()函数的端点处我们想要查看数据包的源地址,即利用下列命令display ih->saddr()
结果如下图所示,即数据包源地址为0,目的地址为2.
6. 删除变量或函数值显示
命令格式:d d 1
其中d---delete
display
d---
变量编号
1---
使用命令”d d 1”即删除第一个变量显示。这是在单步调试的时候将不再显示ih->saddr(),否则如果不删除将显示所有的。
7. 单步执行
命令格式:n
即next
8. 单步跳入
命令格式:s
即step
如下图所示,在执行到下面代码的时候,执行s命令
则跳转到daddr()函数
9.循环执行
命令格式:c
即continue
10.下面介绍的命令是非常有用的,列出运行栈的内容。
命令格式 bt
主要针对的是如果你遇到segment fault的时候,你可以用以上命令,确定在那个为止出问题,以及函数之间的调用关系,后面会具体说明的。
11. 退出调试
命令格式 q
其他的相关命令可以参看手册,不过调试NS2以上的命令基本上已经够用了。
调试示例
示例一、调试segmentation fault
为了具有普遍性,我特意在https://www.wendangku.net/doc/fd7143564.html,添加了一个segmentation fault
添加方法:
1. 打开https://www.wendangku.net/doc/fd7143564.html,,添加头文件
#include "mac-802_11.h"
如下图所示:
2.在recv()函数中开头添加下面的代码引入segmentation fault错误:
3. 重新编译NS2,是错误生效。在ns-2.2*/目录下输入make
4. 在xwin窗口中运行脚本,路由协议必须为AODV,以wireless1.tcl为例。运行后产生,下列错误:
5. 利用gdb确定错误的位置
(在xwin窗口)输入gdb ns,进入调试状态。
1)
在gdb中运行脚本,便会在出错的地方停止程序,如下图所示:
2)
3)如果你想进一步知道在什么地方调用这个函数出错的,可以使用bt命令,具体结果如下图所示。
当然有些错误没这么明显找到的,可能显示的错误是系统文件,这时候你就需要仔细的分析运行栈中的内容,一般的方法是观察运行栈中的函数调用,看看哪一个是你修改的函数,然后将断点设在相应位置,然后重新开始调试,一般都可以找出错误的原因,这就需要你足够的耐性了。
4) 通过上面的步骤我们就确定了错误的位置,然后将最开始我们修改的去掉就OK了。
注释掉我们引入的错误:
重新编译,(注意,一定要退出gdb,否则编译会出错的)首先退出gdb调试状态
然后重新编译 make
如果出现下面界面,即编译成功。
重新运行我们的脚本wireless1.tcl,就不会出现刚才的错误了。如下图所示:
示例二、逻辑错误的调试
说明,一般遇到的都是segmentation fault错误,但并非是这个错误没有了你的程序就完全OK了,还需要调试逻辑错误,就是跟踪某个数据包,看他是否按照你设计的流程去走,这个一般我是通过跟踪数据包的地址实现的。即下图所示。
具体的步骤我就不写了,太多了,我介绍一下思路:
1. 在节点内各协议之间的发送,这个需要你熟悉下图的结构,一般断点设在各
层协议的recv()函数之内,然后你逐层的跟踪就可以确定问题出现在那个协议上了,这个是体力活,呵呵。
2. 节点之间的发送
这个你仔细分析一下https://www.wendangku.net/doc/fd7143564.html,文件中的sendUp()函数就明白了,注意有两个同名的函数,都看看。节点之间发送数据就是通过这个函数,我一般设置端点都在这个函数中。