错误代码分析
作者:lzqlgq@gmail.com
简介
" google不是万能的,没有google是万万不能的 "
很多人人觉得使用ns2 debug 时,错误提示很乱,无从下手,很难找到错误根源,一个好的办法是使用google搜索,确实只要你有耐心,很多问题使用google都可以找到答案,但是google不是万能的,所以自己从错误提示找出错误,改正错误的方法更重要 本文就是以一次错误为例找到错误的根源,错误改正于具体情况有关,不在本文将界范围之内。
错误代码格式
错误代码从错误发生时开始输出,然后返回上一级调用,上一级可能继续返回错误代码的相关信息,最典型的模式是
1 "eval $self create-wireless-node $args" # 命令代码
2 (procedure "_o3" line 23) # 命令所在行数
3 (Simulator node line 23) # Simulator 实体的node函数体
4 invoked from within #
5 "$ns_ node" # 调用代码
此5行大体意思是, 1行对应的命令是从句柄为 "_o3"的Simulator实体的函数 node "函数定义"的第23行调用的
句柄说明
在每一个Simulator对应的模拟中"_o*"标示唯一的一个分裂类实体,也就是说,所有的分裂类实体都有自己的唯一标识 详见《tclcl-1.19/tcl-object.tcl 代码分析 》
对于下面错误代码中提到的几个句柄说明如下:
_o3 是一个Simulator实例句柄, _o14是一个node实例句柄,_o17是一个agent实例句柄
错误例子:
INITIALIZE THE LIST xListHead
1 (_o17 cmd line 1)
2 invoked from within
3 "_o17 cmd port-dmux _o26"
4 invoked from within
5 "catch "$self cmd $args" ret"
6 invoked from within
7 "if [catch "$self cmd $args" ret] {
8 set cls [$self info class]
9 global errorInfo
10 set savedInfo $errorInfo
11 error "error when calling class $cls: $args" $..."
12 (procedure "_o17" line 2)
13 (SplitObject unknown line 2)
14 invoked from within
15 "$agent port-dmux $dmux_"
16 (procedure "_o14" line 11)
17 (Node/MobileNode add-target-rtagent line 11)
18 invoked from within
19 "$self add-target-rtagent $agent $port"
20 (procedure "_o14" line 23)
21 (Node/MobileNode add-target line 23)
22 invoked from within
23 "$self add-target $agent $port" //$self 调用类似于动态运行时
24 (procedure "_o14" line 15)
25 (Node attach line 15)
《attach 函数15行果然是"$self add-target $agent $port" ,计算行数不算注释,空格要算》
26 invoked from within
27 "$node attach $ragent [Node set rtagent_port_]" 此时 "$ node = = _o14"
28 (procedure "_o3" line 75)
29 (Simulator create-wireless-node line 75)
30 invoked from within
31 "_o3 create-wireless-node" // _o3 是Simulaor的一个实体句柄
32 ("eval" body line 1)
33 invoked from within
34 "eval $self create-wireless-node $args" #$self = = "-o3"
35 (procedure "_o3" line 23)
36 (Simulator node line 23)
37 invoked from within
38 "$ns_ node"
39 ("for" body line 2)
40 invoked from within
41 "for {set i 0} {$i < $val(nn) } {incr i} {
42 set node_($i) [$ns_ node]
43 $node_($i) random-motion 0;
44 }"
45 (file "mflood-3nodes.tcl" line 61)
错误分析过程(自底向上)
其实tcl中的self 相当于 C++中的this指针,了解C++的肯定知道,this指针有一个运行时的问题,"this command"可能动态调用父类< 或者子类? > 的同名command,具体的分析采用从下向上方法,如果你很熟悉ns2机制,可以越过一些,具体的分析如下:
1. 41-44给出错误从脚本附近的代码,在一个for循环中, 38行说明"$ns_ node"是来自42行
当在tcl脚本里调用如下:
1 set ns_ [new Simulator]
2 set node_(0) [$ns_ node] ;#调用了Simulator instproc node 过程
//ns-2.31/tcl/lib/ns-lib.tcl
Simulator instproc node args { // args 为域参数
$self instvar Node_ routingAgent_ wiredRouting_ satNodeType_
if { [Simulator info vars EnableMcast_] != "" } {
warn "Flag variable Simulator::EnableMcast_ discontinued./n/t/
Use multicast methods as:/n/t/t/
% set ns /[new Simulator -multicast on]/n/t/t/
% /$ns multicast"
$self multicast #$self = = "-o3"
Simulator unset EnableMcast_
}
... ... ... ... ... ... ... ... ... ... ...
if { [info exists routingAgent_] && ($routingAgent_ != "") } {
23 set node [eval $self create-wireless-node $args] #$self = = "-o3"
#使用eval 是从tcl脚本调用Otcl对象及函数 就是"_o3 create-wireless-node"
... ... ... ... ... ... ... ... ... ... ...
}
return $node //出口之一
}
#分析一下下句语法 & Node_(*)是干什么用的?
set node [eval new [Simulator set node_factory_] $args]
set Node_([$node id]) $node
#把节点加入到Simulator的C++空间的链表中
$self add-node $node [$node id]
#set the nodeid in c++ Node - ratul
$node nodeid [$node id]
$node set ns_ $self //指向模拟器实例
$self check-node-num
return $node
}
2 34-37行可知,调用进入函数 $self create-wireless-node ,31-33指明了"_o3 create-wireless-node" 也就是下面函数,在此 _o3 是Simulaor的一个实体句柄
//ns-2.31/tcl/lib/ns-lib.tcl
Simulator instproc create-wireless-node args {
//omit some code here... ... ... ... ... .. .... ... ... ... ... ... ... ... ...
Simulator set IMEPFlag_ OFF
# create node instance
set node [eval $self create-node-instance $args]
... ... ... ... ... .. .... ... ... ... ... ... ... ... ... //omit some code here
# Attach agent
if {$routingAgent_ != "DSR"} {
$node attach $ragent [Node set rtagent_port_]
}
... ... ... ... ... .. .... ... ... ... ... ... ... ... ...
return $node
}
27 "$node attach $ragent [Node set rtagent_port_]" 此时 "$ node = = _o14"
28 (procedure "_o3" line 75)
29 (Simulator create-wireless-node line 75)
30 invoked from within
31 "_o3 create-wireless-node"
3. 27-30 可知 $node attach $ragent [Node set rtagent_port_] 在上面函数的75行
//ns-2.31/tcl/lib/ns-node.tcl
Node instproc attach { agent { port "" } } {
.......................................................
$agent set agent_port_ $port
15 $self add-target $agent $port
}
23 "$self add-target $agent $port"
24 (procedure "_o14" line 15)
25 (Node attach line 15)
26 invoked from within
27 "$node attach $ragent [Node set rtagent_port_]"
4. 23-25行 可知self add-target $agent $port 来自Node attach函数的15行
19-23行可知 动态转向了Node/MobileNode <-o14> 的add-target, 函数的23行,这里的node其实是一个移动节点Node/MobileNode 类型的,所以调用的是下面的函数
Node/MobileNode instproc add-target { agent port } {
$self instvar dmux_ imep_ toraDebug_
set ns [Simulator instance]
set newapi [$ns imep-support]
$agent set sport_ $port
... ... ... ... ...
if { $port == [Node set rtagent_port_] } {
# Ad hoc routing agent setup needs special handling
23 $self add-target-rtagent $agent $port
return
}
... ... ... ... ...
}
19 "$self add-target-rtagent $agent $port"
20 (procedure "_o14" line 23)
21 (Node/MobileNode add-target line 23)
22 invoked from within
23 "$self add-target $agent $port"
5. $self add-target-rtagent $agent $port
Node/MobileNode instproc add-target-rtagent { agent port } {
$self instvar imep_ toraDebug_
set ns [Simulator instance]
set newapi [$ns imep-support]
set namfp [$ns get-nam-traceall]
set dmux_ [$self demux]
set classifier_ [$self entry]
# let the routing agent know about the port dmux
$agent port-dmux $dmux_
... ... ...省略一些代码 ... ... ...
}
15 "$agent port-dmux $dmux_"
16 (procedure "_o14" line 11)
17 (Node/MobileNode add-target-rtagent line 11)
18 invoked from within
19 "$self add-target-rtagent $agent $port"
6 15-19可以知调用."$agent port-dmux $dmux_" 但是agent 没有函数port-dmux ,agent 的祖先也没有次函数,所以转到 -> MFlood port-dmux $dmux_
但是MFlood也没有定义次函数,所以问题在这里,没有相应的处理代码,这里最主要的是要学会看代码。
[1] 请参考《 ns-2.31下实现mflood .doc》本分析系其中错误基础上所作分析 仅供参考