2.调试器 | 2. Debugger
2调试器
2.1开始
要使用调试器,基本步骤如下:
第1步。
通过调用启动调试器debugger:start()
。
将Monitor window
显示有关所有调试
过程,解释
模块和选定选项的信息。最初通常没有调试
过程。首先,必须指定哪些模块将被调试
(也称为解释
)。按以下步骤进行:
步骤2.在Monitor窗口中选择Module> Interpret 。
该Interpret Modules window
显示。
第3步。
从解释对话框窗口中选择适当的模块。
注意
只有用选项debug_info
集编译的模块才能被解释。“解释模块”窗口中的括号内会显示不可解释的模块。
步骤4. 在Monitor窗口中,选择Module>要解释的模块> View。
源文件的内容显示在View Module window
。
第5步。
设置breakpoints
,如果有的话。
步骤6.
启动要调试的程序。这是从 Erlang shell 正常完成的。
执行解释模块中的代码的所有进程都显示在监视器窗口中。
第7步。要附加到其中某个进程,请双击它,或者选择进程,然后选择进程>附加。附加到流程打开了Attach Process window这个过程。
第8步。
从Attach Process窗口,您可以控制流程执行,检查变量值,设置断点等。
2.2 断点和断点对话窗口
一旦解释了适当的模块,就可以在源代码中的相关位置设置断点。断点是以行为基础指定的。当进程到达断点时,它停止并等待用户的命令(步骤
,跳过
,继续
...)。
注意
当进程到达断点时,只有该进程停止。其他进程不受影响。
使用 Monitor 窗口,View Module 窗口或 Attach Process 窗口的 Break
菜单创建和删除断点。
可执行行
要产生效果,必须在可执行行
设置断点,该行是包含可执行表达式(如匹配或函数调用)的代码行。在case
语句或receive
语句中包含注释,函数头或模式的空白行或行不可执行。
在以下示例中,第2,4,6,8和11行是可执行的行:
1: is_loaded(Module,Compiled) ->
2: case get_file(Module,Compiled) of
3: {ok,File} ->
4: case code:which(Module) of
5: ?TAG ->
6: {loaded,File};
7: _ ->
8: unloaded
9: end;
10: false ->
11: false
12: end.
状态和触发器操作
断点可以是活性
或无活性
。非活动断点被忽略。
每个断点都有一个触发器动作
,用于指定进程到达(并停止)时发生的事情:
启用
- 断点保持活动状态(默认)。
禁用
- 断点将变为非活动状态。
删除
- 断点将被删除
。
线路断点
线路断点在模块的某一行中创建。
图2.1:换行符对话窗口
右键单击模块
条目打开一个弹出菜单,从中可以选择适当的模块
。
当模块显示在“查看模块”窗口或“附加处理”窗口中时,也可以通过双击该行来创建(并删除)断点。
条件断点
在模块中的某一行创建条件断点,但只有在指定的条件为真时才会停止到达断点的进程。
条件由用户指定为模块名称CModule
和函数名称CFunction
。当进程到达断点时,CModule:CFunction(Bindings)
进行评估。当且仅当此函数调用返回时true
,该过程停止。如果函数调用返回false
,断点将被忽略。
Bindings
是变量绑定的列表。要检索Variable
(作为原子给出)的值,请使用函数int:get_binding(Variable,Bindings)
。该函数返回unbound
或{value,Value}
。
图2.2:条件中断对话窗口
右键单击模块
条目打开一个弹出菜单,从中可以选择适当的模块
。
例子:
c_test:c_break/1
模块中的第6行添加了条件断点调用fact
。每次到达断点时,都会调用该函数。当N
等于3时,函数返回true
并且过程停止。
提取自fact.erl
*
5. fac(0) -> 1;
6. fac(N) when N > 0, is_integer(N) -> N * fac(N-1).
定义c_test:c_break/1
*
-module(c_test).
-export([c_break/1]).
c_break(Bindings) ->
case int:get_binding('N', Bindings) of
{value, 3} ->
true;
_ ->
false
end.
功能断点
函数断点是一组行断点,一个位于指定函数的每个子句的第一行。
图2.3:功能中断对话窗口
要打开一个可从中选择适当模块
的弹出式菜单,请右键单击模块
条目。
要在列表框中显示模块的所有功能,请在指定模块名称时单击确定
按钮(或按 Return
或 Tab
键)。
2.3 堆栈跟踪
Erlang 仿真器跟踪堆栈跟踪
,以及有关最近函数调用的信息。如果发生错误,则使用此信息,例如:
1> catch a+1.
{'EXIT',{badarith,[{erlang,'+',[a,1],[]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,573}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,357}]},
{shell,exprs,7,[{file,"shell.erl"},{line,674}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,629}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,614}]}]}}
有关堆栈跟踪的详细信息,请参阅Errors and Error Handling
Erlang参考手册中的一节。
调试器通过跟踪最近调用的解释函数来模拟堆栈跟踪。(真正的堆栈跟踪不能使用,因为它显示调试器的哪些功能已被调用,而不是哪些解释功能。)
这些信息可以用来遍历函数调用链,使用中的向上
和向下
按钮Attach Process window
。
默认情况下,调试器仅保存有关递归函数调用的信息,即尚未返回值的函数调用(选项Stack On,No Tail
)。
然而,有时候,保存所有的呼叫,甚至是尾递归调用都是有用的。这是通过Stack On,Tail
选项完成的。注意,当有很多尾递归调用时,这个选项会消耗更多的内存并减慢解释函数的执行速度。
要关闭调试器堆栈跟踪工具,请选择选项堆栈关闭
。
注意
如果发生错误,在这种情况下,堆栈跟踪变为空。
有关如何更改堆栈跟踪选项的信息,请参见部分Monitor Window
。
2.4 监视器窗口
监视器窗口是调试器的主窗口,并显示以下内容:
- 包含所有解释模块名称的列表框双击模块将打开“查看模块”窗口。
- 选择哪些选项
- 有关所有调试过程的信息,即所有在解释模块中已经或正在执行代码的过程
图2.4:监视窗口
该自动连接
盒,堆栈跟踪
标签,返回跟踪大小
的标签,字符串
框中显示一些选项设置。有关这些选项的详细信息,请参见部分Options Menu
。
过程网格
PID
进程标识符。
初始呼叫
这个过程首先调用一个解释函数。(Module:Function/Arity
)
Name
注册名称,如果有的话。如果未显示注册名称,可能是调试器在注册名称之前收到有关该过程的信息。尝试选择编辑>刷新。
状态
目前的状态如下:
idle
解释函数调用已经返回一个值,并且该进程不再执行解释代码。
running
该过程正在运行。
waiting
这个过程正在一个receive
声明中等待。
中断
该过程在断点处停止。
出口
该过程已终止。
no_conn
没有连接到进程所在的节点。
信息
更多信息,如果有的话。如果进程在断点处停止,则该字段包含有关该位置的信息{Module,Line}
。如果进程已终止,则该字段包含退出原因。
文件菜单
载入设定...
尝试从之前使用保存设置
保存的文件加载和恢复调试器设置(见下文)。任何错误都会被忽略。
请注意,由 Erlang / OTP R16B01 或更高版本保存的设置不能被 Erlang / OTP R16B 或更早版本读取。
保存设置
将调试器设置保存到文件。这些设置包括一组解释文件,断点和所选选项。这些设置可以在以后的调试器会话中使用 Load Settings
(见上文)恢复。任何错误都会被忽略。
Exit
停止调试器。
编辑菜单
Refresh
更新关于调试过程的信息。有关所有已终止进程的信息将从窗口中删除。关闭已终止进程的所有附加进程窗口。
Kill All
使用终止窗口中列出的所有进程exit(Pid,kill)
。
模块菜单
解读
打开Interpret Modules window
,可以指定要解释的新模块。
删除所有
停止解释所有模块。在解释模块中执行的进程终止。
对于每个解释的模块
,相应的条目将添加到模块
菜单中,并带有以下子菜单:
删除
停止解释所选模块。在此模块中执行的进程终止。
View
打开一个View Module window
,显示所选模块的内容。
处理菜单
以下菜单项适用于当前选定的进程,前提是它在断点处停止(有关详细信息,请参见部分Attach Process window
):
StepNextContinueFinish
以下菜单项适用于当前选定的进程:
Attach
附加到过程并打开一个Attach Process window
。
Kill
终止使用过程exit(Pid,kill)
。
中断菜单
此菜单中的项目用于创建和删除断点。有关详情,请参阅部分Breakpoints
。
越线
设置一个线断点。
有条件的休息
设置一个条件断点。
功能中断
设置功能断点。
全部启用
启用所有断点。
禁用所有
禁用所有断点。
删除所有
删除所有断点。
对于每个断点,将相应的条目添加到Break
菜单,从中可以禁用,启用或删除断点并更改其触发器操作。
选项菜单
跟踪窗口
将区域设置为在Attach Process window
。中可见。不影响现有的附加过程窗口。
自动连接
设置调试过程自动附加的事件。影响现有的调试过程。
第一次调用
- 一个进程首次调用解释模块中的函数。
退出时
- 进程终止时。
中断
- 当一个进程到达一个断点时。
堆栈跟踪
设置堆栈跟踪选项,请参见部分Stack Trace
。不影响现有的调试过程。
堆叠,尾巴
- 保存关于当前所有呼叫的信息。
Stack On,No Tail
- 保存关于当前呼叫的信息,当进行尾递归调用时丢弃先前的信息。
堆叠关闭
- 不保存关于当前通话的任何信息。
字符串
设置要作为字符串打印的整数列表。不影响现有的调试过程。
- + PC标志的使用范围 -使用由设定的可打印字符范围erl(1)标志+pc。返回跟踪大小...设置从附加处理窗口检查调用堆栈时要获取多少个调用帧。不影响现有的附加过程窗口.Windows Menu为每个打开的调试器窗口包含一个菜单项。选择其中一个项目会产生相应的窗口。帮助菜单帮助显示调试器文档。此功能需要Web浏览器。2.5解释模块窗口解释模块窗口用于选择要解释的模块。最初,该窗口显示erl当前工作目录的模块(文件)和子目录。可解释模块是为其.beam使用选项debug_info集编译的文件与源代码位于同一目录中,或位于其ebin旁边的目录中。未满足这些要求的模块不可解释,因此显示在括号内。选项debug_info会导致调试信息或摘要代码被添加到.beam文件中。这增加了文件大小,并可以重建源代码。因此,建议不要将调试信息包含在针对目标系统的代码中。例如,如何使用调试信息编译代码erlc:%erlc + debug_info module.erl一个如何用Erlang外壳的调试信息编译代码的例子:4> c(module,debug_info)。图2.5:解释模块窗口要浏览文件层次并解释合适的模块,可以选择模块名称并单击选择(或按回车键),或者双击模块名称。解释模块具有类型erl src。要解释所选目录中的所有显示模块,请单击全部。要关闭该窗口,请单击完成。注意当调试器以全局模式启动时(默认情况下,请参阅debugger:start/0),在所有已知的Erlang节点上添加(或删除)用于解释的模块(或删除)。2.6附加过程窗口从附加过程窗口,您可以与调试过程进行交互。为每个已连接的进程打开一个窗口。请注意,附加到进程时,其执行会自动停止。图2.6:附加进程窗口窗口分为以下五部分:
- 代码区域,显示正在执行的代码。代码是缩进的,每一行都以其行号作为前缀。如果进程执行停止,当前行将被标记为-->.在行处的现有断点用停止符号标记。在插图中显示的示例中,执行在第6行停止,然后执行fac/1...
活动断点以红色显示,非活动断点以蓝色显示。
- 按钮区域,其中有按钮,用于快速访问
加工过程
菜单。
- 如果进程执行停止,则可以在已调试进程的上下文中对函数进行评估。
- 绑定区域,显示所有变量绑定。如果单击变量名,则该值将显示在计算程序区域中。双击一个变量名,打开一个窗口,在其中可以编辑变量值.。但是,请注意,PID、端口、引用或乐趣值不能被编辑,除非它们可以在运行的系统中表示。
- 跟踪区域,它显示进程的跟踪输出。
++ (N) <L>函数调用,其中N是调用级别和L行号。-- (N) 函数返回值
==> Pid : Msg该消息Msg被发送到进程Pid。<== Msg该消息Msg已收到。++ (N) receive在等待中receive。++ (N) receive with timeout在等待中receive...after。Trace区域还显示Back Trace,堆栈上当前函数调用的摘要。
使用选项
菜单,您可以设置要显示的区域。默认情况下,将显示除跟踪区域之外的所有区域。
文件菜单
密闭
关闭此窗口并脱离进程。
编辑菜单
排队..。
转到指定的行号。
搜索...
搜索指定的字符串。
过程菜单
Step
执行当前的代码行,进入任何(解释的)函数调用。
下一个
执行当前的代码行并停在下一行。
继续
继续执行。
Finish
继续执行,直到当前函数返回。
跳跃
跳过当前代码行并停在下一行。如果用在函数体的最后一行,则函数返回skipped
。
时间到
执行receive...after
语句时模拟超时。
停止
停止正在运行的进程的执行,也就是使进程在断点处停止。该命令在下次进程收到消息时生效(明显)。
Where
验证执行的当前位置在代码区域中是否可见。
Kill
终止使用过程exit(Pid,kill)
。
消息
检查进程的消息队列。该队列显示在评估程序区域中。
返回跟踪
在“跟踪”区域中显示进程的反向跟踪,堆栈上当前函数调用的摘要。要求Trace区域可见并且Stack Trace选项为Stack On,Tail
或Stack On,No Tail
。
向上
检查堆栈上的前一个函数调用,显示位置和变量绑定。
下
检查堆栈上的下一个函数调用,显示位置和变量绑定。
选项菜单
跟踪窗口
设置哪些区域是可见的。不影响其他附加处理窗口。
堆栈跟踪
与在中相同Monitor window
,但仅影响窗口所连接的调试过程。
字符串
与在中相同Monitor window
,但仅影响窗口所连接的调试过程。
返回跟踪大小
设置在检查调用堆栈时将获取多少调用帧。不影响其他附加进程窗口。
“中断”、“窗口”和“帮助”菜单
该中断
,视窗
和帮助
菜单是一样的Monitor Window
,只是休息
菜单只适用于本地断点。
2.7 查看模块窗口
查看模块窗口显示解释模块的内容,并可以设置断点。
图2.7:查看模块窗口
源代码是缩进的,每行都以其行号作为前缀。
点击一行突出显示它并选择它是可以从断点功能目标歇
菜单。要在一条线上设置线断点,请双击它。要删除断点,请双击带有现有断点的行。
断点标有停止符号。
文件和编辑菜单
“ 文件”
和“ 编辑”
菜单与“ 文件”
菜单中的相同Attach Process Window
。
“中断”、“窗口”和“帮助”菜单
该休息
,视窗
和帮助
菜单是一样的Monitor Window
,不同之处在于打破
菜单只适用于本地断点。
2.8性能
解释代码的执行速度自然慢于定期编译的模块。使用调试器还会增加系统中的进程数量,因为每个调试进程都会创建另一个进程(元进程)。
同样值得一提的是,调试时带定时器的程序可能会有不同的表现。停止执行进程时(例如,在断点处),尤其如此。然后在其他进程中发生超时,这些进程可以像平常一样继续执行。
2.9码加载机构
代码加载的工作方式与往常一样,只是解释的模块也存储在数据库中,而调试的进程只使用此存储的代码。重新解释解释模块也会导致新版本被存储,但不会影响执行旧版本代码的现有进程。这意味着Erlang的代码替换机制不适用于调试的进程。
2.10调试远程节点
通过使用debugger:start/1
,您可以指定调试器是以本地还是全局模式启动:
debugger:start(local | global)
如果没有提供参数,调试器以全局模式启动。
在本地模式下,代码仅在当前节点解释。在全局模式下,代码在所有已知节点处被解释。执行解释代码的其他节点上的进程会自动显示在“监视器”窗口中,并可像其他任何调试过程一样附加进程。
可能但肯定不推荐在网络中的多个节点上以全局模式启动调试器,因为节点互相干扰,导致行为不一致。