NS2从安装到调试系列记录---之调试篇

来源:互联网 发布:人工智能中医 编辑:程序博客网 时间:2024/05/16 21:07

转自http://hi.baidu.com/aoxinguy/blog/item/4eb310184d545373dbb4bd5f.html

对应着NS2的两种支撑语言:NS2中的程序调试也可以分为两个层次,一个是在脚本层的调试,另一个是在C++代码层调试。

脚本层的调试,目前对于 TCL语言最成功的应该算是 tcl-debug,版本为2.0(不大确定)? 它的安装也是非常简单。其具体操作已经转到本博客的: http://hi.baidu.com/aoxinguy/blog/item/7cc427fdde0bef8bb801a06f.html

下面主要讲一下在C++代码层次的调试。这个层次的调试在实际NS2的编程工作中应该经常要用到。

1. 首先 C++代码层的调试其基本原理就是在用gcc 编译时 额外将一些辅助调试信息加入到生成的.o文件中去。 (一般在Makefile中编译选项处添加 -g,或者在./configure 时用 --enable-debug 选项)。这样在程序调试时,通过添加进去的辅助信息才可以追踪到程序运行处所对应的源代码文件具体位置以及其它相关信息。 在linux下调试工具或者说是读这些调试信息的工具,无非就是gdb了。GDB的功能很强大,本身通过命令行形式完成各种如堆栈查看等相关调试工作。

2. 虽然 GDB 很强大,但其实在一般的调试中,我们所用到的功能也非常有限。而且,其命令行形式,虽然灵活,但方便不足。 理想的VC6流畅的调试体验通过GDB一行行的命令实在难以获得。然而,在unbuntu下,有一些IDE工具可以帮助我们接近这种体验,如KDevelop 和 Eclipse+CDT等~ 这些IDE工具其本质上也是在调用linux系统中本身的gdb工具,只不过,它们将这些命令行通过IDE中友好的用户界面包装好,从而为我们提供了比较好的调试体验。

3. 可能是因为以前经常用VC6分析MFC的框架的缘故,理想中我也非常希望NS2在eclipse的帮助下,能够获得相同的调试体验,那就是:自由地在跟踪整个NS2框架从初始化到仿真脚本执行完中涉及到的全部源代码流。 这样的好处不言而喻:一来可以对NS2的框架有更深、更透彻的了解;二来,通过跟踪仿真流程,可以对某个具体协议的运行有着更立体化的认识,从而加深对理论的认识。其实,我初期研究NS2的大部分工作都是为了达成这一个理想体验。

本人比较推荐的是用 Eclipse eura +CDT 3.0 (?) 它的安装说明将在另一个专贴中说明

在我们按照 NS2从安装到调试系列记录---之安装篇 的内容 安装好 NS2并配置好bash后,打开eclipse,选择新建 New C++ project,工程目录选择ns-allinone-2.* 下面的 ns2.* 目录,工程类型选择 makefile Project

这时,我们发现当我们需要在 TclMain.cc文件中添加断点时,老会提示: stopped due to shared dll event,而且一按开始调试,IDE的终端端口会直接跳至NS2的提示符输出界面(此时要求用户输入仿真脚本)。我们甚至跟踪不到NS2程序的入口函数。 这离我的理想体验差之万里,因为直接跳至NS2的提示符输出界面意味着无法跟踪到这之前的所有初始化工作,包括TCLClass静态类的初始化,TCL引擎的建立等~

其实,遇到这个问题的原因在于: 安装NS2时,install 程序在编译ns2.* 目录下的文件时,并没有将调试信息加入。 为此,我们需要跳至 ns2.* 目录下,先用make clean命令清除先前install生成的旧目标文件、库文件和可执行文件。然后,再用sudo ./configure --enable-debug 命令将调试信息添加进去(这个configure 命令实际上是生成Makefile文件,--enable-debug参数相当直接在Makefile文件中的编译选项中添加 -g 选项 ) 再然后,用make命令生成新的目标、库和可执行文件ns2。

{在ns2.31的版本下,重新编译NS2时,会出现以下错误:

    这个错误的解决办法 是 找到

   这个错误的解决办法是找到 wireless-phy.cc这个文件,然后 将#define MAX ** 换成

   #ifndef MAX

   #define MAX ***

   #endif

   然后,再重新make一下便可.

这时,我们重回eclispe,刷新一下工程,然后,再次进行调试,出现如下图所示结果:

   这时,我们可以发现代码已经跳入到NS2程序的入口点:main函数, (位于ns2.*目录的common子目录的TclAppInit.cc文件)

     main函数中只有两句代码

                  Tcl_Main(argc, argv, Tcl_AppInit);

                   return 0;

   这个函数可以说包装了整个NS2框架,因为紧接着它的下一句语句就是:return 0!

然而,此时,当我们想通过F5(单步跳入)查看TclMain函数的具体实现时,IDE的终端又直接跳至提示符。也就是说,我们仍然无法查看Tcl_Main函数的原型,也就无法查看NS2框架的大部分内容。

我们能查看到 main函数的实现却看不到Tcl_main函数的实现的原因在于: Tcl_Main函数所在的文件并非位于ns2.*目录下,而是位于另一个目录下(后面将看到是tcl8.4.*目录的unix子目录)。 而且Tcl_Main函数是被编译到一个静态链接库文件中去了(后面我们将知道是libtcl8.*.a)。 我们此时,只是在ns2.*目录下,用./configure --enable-debug 添加了调试信息,但却没有在 Tcl_Main 函数所在有 tcl8.4.*目录下 添加调试信息(具体来说是在tcl8.4.*的unix目录下的Makefile文件中添加 -g选项)

为了能够跟踪到Tcl_Main函数中去,我们作如下操作:

切换到 tcl8.4.*目录的unix子目录,然后 我们会发现 里面有一个libtcl8.*.a 和另一个libtclstub.*.a 文件,前一个大小为700多K(这其实是未添加调试信息前的大小)。 再次用make clean命令清除所有目标、库文件后,我们不能再次用sudo ./configure --enable-debug 命令来添加 调试信息(其原因在于此处的 Makefile.in 文件有些特殊)。 我们所要做的是 将 Makefile文件中的 下面内容(102-106行)

# To change the compiler switches, for example to change from optimization to
# debugging symbols, change the following line:
#CFLAGS    = $(CFLAGS_DEBUG)
#CFLAGS    = $(CFLAGS_OPTIMIZE)
#CFLAGS    = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE)
CFLAGS    = $(CFLAGS_OPTIMIZE) -DTCL_DBGX=$(TCL_DBGX)

换成

# To change the compiler switches, for example to change from optimization to
# debugging symbols, change the following line:
#CFLAGS    = $(CFLAGS_DEBUG)
#CFLAGS    = $(CFLAGS_OPTIMIZE)
CFLAGS    = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE)
#CFLAGS    = $(CFLAGS_OPTIMIZE) -DTCL_DBGX=$(TCL_DBGX)

其意思是 将编译械从原来的 优化模式 切换 到 DEBUg+ OPTIMIZE模式。相当于 前面所讲 的 在CCOPT 后添加 -g 选项

然后 ,再次 make ,生成两个新的.a 文件.

注意:在unix目录生成新的.a文件后,须将这两个文件拷贝至 ns-allinone-2.3*的lib目录下(因为,在生成NS2时,指定的libtcl8.*.a 的库路径为lib)

其实,我们在用make 命令生成NS时,从终端的输出便可以知道NS引用了哪些静态库。为了能够全程调试,这些静态库都应该如libtcl8.*.a库一样,添加调试信息后重新编译生成。

添加调试信息无非就是更改对应的Makefile 中的gcc 编译选项(不同库的Makefile不相同,有的库用 ./configure --enable-debug命令不能添加 调试信息,必须手动修改Makefile)

另外,还需要注意的是:NS所依赖的这些静态库实际上是有相互依赖关系的,因此,重新编译它们,也需要按照一定的顺序。这也是为什么 NS的 allinone包在安装各个包时,其顺序都是固定的原因。

详细的信息,可以从本分类下的另一贴"关于NS2所引用的几个静态链接库文件" 获得


原创粉丝点击