当中断命令挂起例程的执行或发生错误时,程序堆栈将保留一些堆栈信息。发生这种情况时,此信息的简要摘要将显示为终端提示符(NAMESPACE>)的一部分。例如,此信息可能采用以下形式:User 5D3>
,其中:
代码 | 描述 |
---|---|
5 |
指示有五个堆栈级别。堆栈级可能由DO 、FOR 、XECUTE 、NEW 、用户定义的函数调用、错误状态或中断状态引起。 |
d |
指示堆叠的最后一项是DO 。 |
3 |
指示堆栈上有3个新状态、参数传递或用户定义函数。如果没有堆叠新命令、参数传递或用户定义函数,则此值为零。 |
下表列出了端子提示字母代码。
提示 | 定义 |
---|---|
d |
DO |
e |
用户定义函数 |
f |
FOR 循环 |
x |
XECUTE |
B |
BREAK 状态 |
E |
Error 状态 |
N |
NEW 状态 |
S |
登录状态 |
在下面的示例中,添加堆栈帧时,将显示命令行语句及其生成的程序员模式提示:
DHC-APP>new
DHC-APP 1S1>XECUTE "NEW WRITE 123 BREAK"
123
NEW WRITE 123 BREAK
^
<BREAK>
DHC-APP 3x1>NEW
DHC-APP 4B1>BREAK
BREAK
^
<BREAK>
DHC-APP 5N2>
可以使用Quit 1
展开程序堆栈。以下是展开堆栈时的终端提示示例:
DHC-APP 5N2>q 1
DHC-APP 4B1>q 1
DHC-APP 3x1>q 1
DHC-APP 2N2>q 1
DHC-APP 1S1>q 1
DHC-APP>
USER 6f0>QUIT 1 /* for循环中出错. */
USER 5x0>QUIT 1 /* For循环位于XECUTE调用的代码中. */
USER 4f0>QUIT 1 /* XECUTE处于FOR循环中. */
USER 3f0>QUIT 1 /* 该for循环嵌套在另一个for循环中. */
USER 2d0>QUIT 1 /* do命令用于执行程序. */
USER 1S0>QUIT 1 /* 登录状态. */
USER>
For
循环和While
循环以使用Fo
r或While
执行相同的操作:循环,直到事件(通常是计数器增量)导致执行中断循环。但是,使用哪个循环构造会导致在代码模块上执行单步(中断“S+
”或中断“L+
”)调试。
for
循环将新级别推送到堆栈上。WHILE
循环不会更改堆栈级别。调试for
循环时,从for
循环内弹出堆栈(使用Break“C”GOTO``或QUIT 1
)允许在for
命令构造结束后立即使用命令继续单步调试。调试While
循环时,发出Using Break“C”GoTo
或Quit 1
不会弹出堆栈,因此单步调试不会在While
命令结束后继续。其余代码在不中断的情况下执行。
在中断或错误后返回到终端提示时,Caché会跟踪导致中断或错误的命令的位置。稍后,只需在终端提示符下输入一个无参数的GOTO
,即可在下一个命令恢复执行:
USER 4f0>GOTO
通过键入带参数的GOTO
,可以在同一例程中带中断或错误的另一行的开头继续执行,如下所示:
USER 4f0>GOTO label3
还可以在不同例程的行首恢复执行:
USER 4f0>GOTO label3^rou
或者,可以使用无参数退出命令清除程序堆栈:
USER 4f0>QUIT
USER>
下面的示例中使用了以下例程。
MAIN ; 03 Jan 2019 11:40 AM
SET x=1,y=6,z=8
DO SUB1 WRITE !,"sum=",sum
QUIT
SUB1 ; 03 Jan 2019 11:42 AM
SET sum=x+y+z
QUIT
使用中断“L”
,中断不会发生在例程SUB1
中。
USER>BREAK "L"
USER>DO ^MAIN
SET x=1,y=6,z=8
^
<BREAK>MAIN+1^MAIN
USER 2d0>GOTO
DO ^SUB1 WRITE !,"sum=",sum
^
<BREAK>MAIN+2^MAIN
USER 2d0>GOTO
sum=15
QUIT
^
<BREAK>MAIN+3^MAIN
USER 2d0>GOTO
USER>
对于中断“L+
”,中断也会发生在例程SUB1
中。
USER>BREAK "L+"
USER>DO ^MAIN
SET x=1,y=6,z=8
^
<BREAK>MAIN+1^MAIN
USER 2d0>GOTO
DO ^SUB1 WRITE !,"sum=",sum
^
<BREAK>MAIN+2^MAIN
USER 2d0>GOTO
SET sum=x+y+z
^
<BREAK>SUB1+1^SUB1
USER 3d0>GOTO
QUIT
^
<BREAK>SUB1+2^SUB1
USER 3d0>GOTO
sum=15
QUIT
^
<BREAK>MAIN+3^MAIN
USER 2d0>GOTO
USER>
无参数的new
命令可以有效地将所有符号保存在符号表中,以便可以继续处理空的符号表。在出错或中断后出现终端提示时,可能会发现此命令特别有用。
要在不干扰符号表的情况下运行其他例程,请在终端提示符下发出不带参数的new
命令。然后,系统会执行以下操作:
例如:
USER 4d0>NEW
USER 5B1>DO ^%T
3:49 PM
USER 5B1>QUIT 1
USER 4d0>GOTO
5b1>
提示表示系统已堆叠了通过分隔符输入的当前帧。1
表示新命令具有堆叠的变量信息,可以通过发出Quit 1
来删除这些信息。当希望恢复执行时,发出Quit 1
以恢复旧符号表,并发出GOTO
以恢复执行。
每当使用新命令、参数传递或用户定义函数时,系统都会将信息放在堆栈上,指示稍后在当前子例程或XECUTE
级别的显式或隐式退出应删除某些变量并恢复其他变量的值。
可能会发现,了解是否执行了任何新命令、参数传递或用户定义函数(从而堆叠了一些变量)是很有用的,如果执行了,那么这些信息在堆栈中的位置有多远。
QUIT
命令在终端提示符下,可以通过输入无参数退出命令从程序堆栈中删除所有项目:
USER 4f0>QUIT
USER>
要仅从程序堆栈中删除几个项目(例如,要离开当前正在执行的子例程并返回到上一个DO
级别),请使用带整数参数的QUIT
。Quit 1
删除程序堆栈中的最后一项,Quit 3
删除最后三项,依此类推,如下所示:
USER 9f0>QUIT 3
USER 6d0>
Caché在尖括号内显示错误消息,如
所示,后跟对发生错误时正在执行的行和例程的引用。插入符号(^
)分隔行引用和例程。还显示了在发生错误时执行的命令的第一个字符下带有插入字符的中间代码行。例如:
SET x=y+3 DO ^ABC
^
<UNDEFINED>label+3^rou
此错误消息指示例程rou的行标签+3
中的
错误(指的是变量y
)。此时,此消息也是特殊变量$ZERROR
的值。
%STACK
显示堆栈可以使用%STACK
实用程序执行以下操作:
$IO
和$JOB
。%STACK
通过输入以下命令可以执行%STACK
:
USER>DO ^%STACK
如本例所示,%STACK
实用程序显示没有变量的当前进程堆栈。
Level Type Line Source
1 SIGN ON
2 DO ~DO ^StackTest
3 NEW ALL/EXCL NEW (E)
4 DO TEST+1^StackTest SET A=1 ~DO TEST1 QUIT ;level=2
5 NEW NEW A
6 DO TEST1+1^StackTest ~DO TEST2 ;level = 3
7 ERROR TRAP SET $ZTRAP="TrapLabel^StackTest"
8 XECUTE TEST2+2^StackTest ~XECUTE "SET A=$$TEST3()"
9 $$EXTFUNC ^StackTest ~SET A=$$TEST3()
10 PARAMETER AA
11 DIRECT BREAK TEST3+1^StackTest ~BREAK
12 DO ^StackTest ~DO ^%STACK
在当前执行堆栈显示下,%STACK
会提示执行堆栈显示操作。可以通过输入问号(?
)获得帮助。在此提示下。在此提示符下按Return键可退出%STACK
。
根据在堆栈显示操作提示符下输入的内容,可以用四种形式显示当前流程执行堆栈:
*F
*V
*P
*A
然后,%STACK
在设备提示符上显示显示,使可以指定此信息的位置。按Return键向当前设备显示此信息。
首次进入%STACK
实用程序或在Stack Display Action(堆栈显示操作)提示符下键入*F
时,会出现不带变量的进程执行堆栈。
在Stack Display Action提示下输入*V
。这将提示输入要在堆栈中跟踪的局部变量的名称。指定单个变量或逗号分隔的变量列表.它返回所有局部变量的名称和值。在下面的示例中,正在跟踪变量e
,并通过按Return将显示发送到终端,
Stack Display Action: *V
Now loading variable information ... 2 done.
Variable(s): e
Display on
Device: <RETURN>
在Stack display Action提示符下输入*P
以查看进程执行堆栈以及所有定义的局部变量的当前值。
在Stack Display Action(堆栈显示操作)提示符下输入*A
以显示所有可能的报告。报告按以下顺序发布:
堆栈上的每个项目都称为框架。下表介绍了为每个帧提供的信息。
头 | 描述 |
---|---|
Level |
标识堆栈中的级别。堆栈上最老的项目是数字1。没有关联标高编号的框架共享首次出现在其上方的标高。 |
Type |
标识堆栈上的帧类型,可以是:直接中断:遇到导致返回到直接模式的中断命令。直接调入:使用Caché调入接口从Caché外部的应用程序启动一个Caché进程。直接错误:遇到导致返回到直接模式的错误。DO :已执行DO 命令。错误陷阱:如果例程设置$ZTRAP ,则此帧标识错误将导致执行继续的位置。FOR :执行了FOR 命令。NEW :执行了NEW 命令。如果新命令有参数,则会显示它们。登录:Caché进程的执行已启动。XECUTE :执行了XECUTE 命令。$$EXTFUNC :执行了用户定义函数。 |
Line |
在格式Label+Offset^ 例程中标识与帧关联的ObjectScript源行(如果可用)。 |
Source |
显示该行的源代码(如果可用)。如果信号源太长,无法在提供的区域中显示,则可以使用水平滚动。如果设备是面向行的,则源自动换行,并在连续行前面加上“. ”。 |
下表显示了级别、线条和源值是否可用于每种帧类型。标高下的"No" 表示标高编号不会递增,并且显示屏中不会显示任何标高编号。
帧类型 | Level |
Line |
Source |
---|---|---|---|
DIRECT BREAK |
Yes | Yes | Yes |
DIRECT CALL IN |
Yes | No | No |
DIRECT ERROR |
Yes | Yes | Yes |
DO |
Yes | Yes | Yes |
ERROR TRAP |
No | No | 不会,但会显示新的$ZTRAP值。 |
FOR |
No | Yes | Yes |
NEW |
No | No | 显示新的形式(包含或排除)和受影响的变量。显示P值。 |
PARAMETER |
No | No | 显示形式参数列表。如果参数是通过引用传递的,则显示指向同一内存位置的其他变量。 |
SIGN ON |
Yes | No | No |
XECUTE |
Yes | Yes | Yes |
$$EXTFUNC |
Yes | Yes | Yes |
如果从终端提示符调用这些参数,则行值为空。
要查看存在于给定堆栈帧级别的变量,请在“Stack display Action”提示符下输入?#
,其中#
是堆栈帧级别。下例显示了如果请求级别1的变量时的显示。
Stack Display Action: ?1
The following Variables are defined for Stack Level: 1
E
Stack Display Action:
可以通过输入??
显示在所有堆栈级别定义的变量。在“Stack Display Action”(堆栈显示操作)提示下。以下示例显示了选择此操作时的示例显示。
Stack Display Action: ??
Now loading variable information ... 19
Base Stack Level: 5
A
Base Stack Level: 3
A B C D
Base Stack Level: 1
E
Stack Display Action:
要显示进程状态变量,如$IO
,请在“Stack display Action”提示符下输入*S
。将看到下表中列出的这些已定义变量(进程状态内部变量):
进程状态内部变量 | 文档 |
---|---|
$D = | $DEVICE 特殊变量 |
$EC = ,M9, | $ECODE 特殊变量 |
$ES = 4 | $ESTACK 特殊变量 |
$ET = | $ETRAP 特殊变量 |
$H = 64700,50668 | HOROLOG 特殊变量 |
$I = |TRM|:|5008 |
$IO 特殊变量 |
$J = 5008 | $JOB 特殊变量 |
$K = $c(13) | $KEY 特殊变量 |
$P = | TRM |
$Roles = %All | $ROLES 特殊变量 |
$S = 268315992 | $STORAGE 特殊变量 |
$T = 0 | $TEST 特殊变量 |
$TL = 0 | $TLEVEL 特殊变量 |
$USERNAME = glenn | $USERNAME 特殊变量 |
$X = 0 | $X 特殊变量 |
$Y = 17 | $Y 特殊变量 |
$ZA = 0 | $ZA 特殊变量 |
$ZB = $c(13) | $ZB 特殊变量 |
$ZC = 0 | $ZCHILD 特殊变量 |
$ZE = | $ZERROR 特殊变量 |
$ZJ = 5 | $ZJOB 特殊变量 |
KaTeX parse error: Undefined control sequence: \Latin at position 8: ZM = RY\̲L̲a̲t̲i̲n̲1\K\UTF8\| `ZMODE` 特殊变量 | |
$ZP = 0 | $ZPARENT 特殊变量 |
$ZR = ^||a |
$ZREFERENCE 特殊变量 |
$ZS = 262144 | $ZSTORAGE 特殊变量 |
$ZT = | $ZTRAP 特殊变量 |
$ZTS = 64700,68668.58 | $ZTIMESTAMP 特殊变量 |
$ZU(5) = USER | $NAMESPACE |
$ZU(12) = c:\intersystems\cache\mgr| NormalizeDirectory() | |
$ZU(18) = 0 | Undefined() |
$ZU(20) = USER | UserRoutinePath() |
$ZU(23,1) = 5 | |
$ZU(34) = 0 | |
$ZU(39) = USER | SysRoutinePath() |
$ZU(55) = 0 | LanguageMode() |
$ZU(56,0) = $Id: //dev/2017.2.1/kernel/common/src/crtnbuf.c#1 $ 0 | |
$ZU(56,1) = 1349 | |
$ZU(61) = 16 | |
$ZU(61,30,n) = 262160 | |
Z U ( 67 , 10 , ZU(67,10, ZU(67,10,J) = 1 | JobType |
Z U ( 67 , 11 , ZU(67,11, ZU(67,11,J) = glenn | UserName |
Z U ( 67 , 12 , ZU(67,12, ZU(67,12,J) = TRM: | ClientNodeName |
Z U ( 67 , 13 , ZU(67,13, ZU(67,13,J) = | ClientExecutableName |
Z U ( 67 , 14 , ZU(67,14, ZU(67,14,J) = | CSPSessionID |
Z U ( 67 , 15 , ZU(67,15, ZU(67,15,J) = 127.0.0.1 | ClientIPAddress |
Z U ( 67 , 4 , ZU(67,4, ZU(67,4,J) = 000 | State |
Z U ( 67 , 5 , ZU(67,5, ZU(67,5,J) = %STACK | Routine |
Z U ( 67 , 6 , ZU(67,6, ZU(67,6,J) = USER | NameSpace |
$ZU(67,7,$J) = |TRM|:|5008 |
CurrentDevice |
Z U ( 67 , 8 , ZU(67,8, ZU(67,8,J) = 923 | LinesExecuted |
Z U ( 67 , 9 , ZU(67,9, ZU(67,9,J) = 46 | GlobalReferences |
$ZU(68,1) = 0 | NullSubscripts() |
$ZU(68,21) = 0 | SynchCommit() |
$ZU(68,25) = 0 | |
$ZU(68,27) = 1 | |
$ZU(68,32) = 0 | ZDateNull() |
$ZU(68,34) = 1 | AsynchError() |
$ZU(68,36) = 0 | |
$ZU(68,40) = 0 | SetZEOF() |
$ZU(68,41) = 1 | |
$ZU(68,43) = 0 | OldZU5() |
$ZU(68,5) = 1 | BreakMode() |
$ZU(68,6) = 0 | |
$ZU(68,7) = 0 | RefInKind() |
$ZU(131,0) = MYCOMPUTER | |
$ZU(131,1) = MYCOMPUTER:CACHE | |
$ZV = Cache for Windows (x86-64) 2017.2.1 (Build 801_1U) Mon Mar 12 2018 22:47:10 EST | $ZVERSION 特殊变量 |
当选择以下操作时,可以选择输出设备:
*P
*A
*V
选择要显示的变量后。还可以使用其他工具来帮助调试过程。这些措施包括:
$SYSTEM.OBJ.ShowReferences
的对象的引用要显示进程符号表中包含对给定对象的引用的所有变量,请使用%SYSTEM.OBJ
类的ShowReferences(OREF)
方法。OREF
是给定对象的OREF
(对象引用)。
错误捕获实用程序%ETN和%ERN通过存储变量和记录有关错误的其他相关信息来帮助进行错误分析。
%ETN
应用程序错误陷阱可能会发现,将错误陷阱设置为对应用程序错误执行实用程序%etn
会很方便。该实用程序在出错时保存有关作业的有价值的信息,如执行堆栈和变量值。此信息保存在应用程序错误日志中,您可以使用%ern
实用程序显示该日志,也可以在管理门户的查看应用程序错误日志页面(系统操作、系统日志、应用程序错误日志)上查看该日志。
使用以下代码将错误陷阱设置为此实用程序:
SET $ZTRAP="^%ETN"
备注:在程序中,不能将$ZTRAP
设置为外部例程。由于此限制,不能在过程(包括属于程序的类方法)中使用^%ETN
。但是,可以将$ZTRAP
设置为调用%ETN
的本地标签。
当发生错误并调用%ETN实用程序时,会看到类似于以下消息的消息:
Error has occurred: at 10:30 AM
因为%ETN
以HALT
命令结束(终止进程),所以可能只想在应用程序模式下使用例程时设置%ETN
错误陷阱。当终端提示符处出现错误时,在终端上显示错误并进入调试器提示符以允许立即分析错误可能很有用。以下代码仅在Caché处于应用程序模式时设置错误陷阱:
SET $ZTRAP=$SELECT($ZJ#2:"",1:"^%ETN")
%ERN
应用程序错误报告%ern
实用程序检查%ETN错误捕获实用程序记录的应用程序错误。
在下面的代码中,发出例程报告的ZLOAD,以说明通过使用“*load
”加载所有变量,然后加载例程,可以重新创建发生错误时作业的状态,但记录有关DoS等信息的程序堆栈是空的。
USER>DO ^%ERN
For Date: 4/30/2018 3 Errors
Error: ?L
1) "zMyTest+2^Sample.MyStuff.1" at 10:27 am. $I=|TRM|:|10044 ($X=0 $Y=17)
$J=10044 $ZA=0 $ZB=$c(13) $ZS=262144 ($S=268242904)
WRITE 5/0
2) <SUBSCRIPT>REPORT+4^REPORT at 03:16 pm. $I=|TRM|:|10044 ($X=0 $Y=57)
$J=10044 $ZA=0 $ZB=$c(13) $ZS=2147483647 ($S=2199023047592)
SET ^REPORT(%DAT,TYPE)=I
3) <UNDEFINED>zMyTest+2^Sample.MyStuff.1 *undef" at 10:13 pm. $I=|TRM|:|12416 ($X=0 $Y=7)
$J=12416 $ZA=0 $ZB=$c(13) $ZS=262144 ($S=268279776)
WRITE undef
Error: 2
2) <SUBSCRIPT>REPORT+4^REPORT at 03:16 pm. $I=|TRM|:|10044 ($X=0 $Y=57)
$J=10044 $ZA=0 $ZB=$c(13) $ZS=2147483647 ($S=2199023047592)
SET ^REPORT(%DAT,TYPE)=I
Variable: %DAT
%DAT="Apr 30 2018"
Variable: TYPE
TYPE=""
Variable: *LOAD
USER>ZLOAD REPORT
USER>WRITE
%DAT="Apr 30 2018"
%DS=""
%TG="REPORT+1"
I=88
TYPE=""
XY="SET $X=250 WRITE *27,*91,DY+1,*59,DX+1,*72 SET $X=DX,$Y=DY"
USER>