This chapter describes the Caché techniques for testing and debugging Caché applications. Its topics include:
An important part of application development is routine debugging: the testing and correcting of program code. Caché gives you two ways to debug your routines:
Use the BREAK
command in routine code to suspend execution and allow you to examine what is happening.
Use the ZBREAK
command to invoke the Caché Debugger
to interrupt execution and allow you to examine both code and variables.
The Caché Debugger
lets you test routines by inserting debugging commands directly into your routine code. Then, when you run the code, you can issue commands to test the conditions and the flow of processing within your application. Its major capabilities are:
Set breakpoints with the ZBREAK
command at code locations and take specified actions when those points are reached.
Set watchpoints on local variables and take specified actions when the values of those variables change.
Interact with Caché during a breakpoint/watchpoint in a separate window.
Trace execution and output a trace record (to a terminal or other device) whenever the path of execution changes.
Display the execution stack.
Run an application on one device while debugging I/O goes to a second device. This enables full screen Caché applications to be debugged without disturbing the application’s terminal I/O.
The Caché Debugger
provides two ways to interrupt program execution:
A breakpoint is a location in a Caché routine that you specify with the ZBREAK
command. When routine execution reaches that line, Caché suspends execution of the routine and, optionally, executes debugging actions you define. You can set breakpoints in up to 20 routines. You can set a maximum of 20 breakpoints within a particular routine.
A watchpoint is a variable you identify in a ZBREAK
command. When its value is changed with a SET
command, you can cause the interruption of routine execution and/or the execution of debugging actions you define within the ZBREAK
command. You can set a maximum of 20 watchpoints.
Breakpoints and watchpoints you define are not maintained from one session to another. Therefore, you may find it useful to store breakpoint/watchpoint definitions in a routine or XECUTE
command string so it is easy to reinstate them between sessions.
You use the ZBREAK
command to establish breakpoints and watchpoints.
||Required. Specifies a code location (that sets a breakpoint) or local or system variable (which sets a watchpoint). If the location specified already has a breakpoint/watchpoint defined, the new specification completely replaces the old one.
||Optional Specifies the action to take when the breakpoint/watchpoint is triggered. For breakpoints, the action occurs before the line of code is executed. For watchpoints, the action occurs after the command that modifies the local variable. Actions may be upper- or lowercase, but must be enclosed in quotation marks.
||Optional Specifies an expression that will be evaluated when the breakpoint/watchpoint is triggered. The expression must be surrounded by quotation marks. If condition is false, the action will not be carried out and the execute_code will not be executed. If condition is not specified, the default is true.
||Optional Specifies ObjectScript code to be executed if condition is true. The code must be surrounded by quotation marks if it is a literal. This code is executed before the action being carried out. Before the code is executed, the value of the $TEST special system variable is saved. After the code has executed, the value of $TEST as it existed in the program being debugged is restored.
with a ? (question mark) displays help.
Setting Breakpoints with Code Locations
You specify code locations as a routine line reference that you can use in a call to the $TEXT
function. A breakpoint occurs whenever execution reaches this point in the code, before the execution of the line of code. If you do not specify a routine name, Caché assumes the reference is to the current routine.
Argumentless GOTO in Breakpoint Execution Code
An argumentless GOTO
is allowed in breakpoint execution code. Its effect is equivalent to executing an argumentless GOTO
at the debugger BREAK
prompt and execution proceeds until the next breakpoint.
For example, if the routine you are testing is in the current namespace, you can enter location values such as these:
If the routine you are testing is currently loaded in memory (that is, an implicit or explicit ZLOAD
was performed), you can use location values such as these:
Setting Watchpoints with Local and System Variable Names
Local variable names cause a watchpoint to occur in these situations:
Variable names are preceded by an asterisk, as in *a
If you specify an array-variable name, the Caché Debugger watches all descendant nodes. For instance, if you establish a watchpoint for array a
, a change to a(5) or a(5,1) triggers the watchpoint.
The variable need not exist when you establish the watchpoint.
You can also use the following special system variables:
||Triggered whenever an error occurs, before invoking the error trap.
||Triggered whenever an error trap is set or cleared.
||Triggered whenever explicitly SET.
Action Argument Values
The following table describes the values you can use for the ZBREAK action
||Default, except if you include the "T" action, then you must also explicitly include the "B" action, as in ZBREAK *a:"TB", to actually cause a break. Suspends execution and displays the line at which the break occurred along with a caret (^) indicating the point in the line. Then displays the Programmer prompt and allows interaction. Execution resumes with an argumentless GOTO command.
||Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each line. When a DO command, user-defined function, or XECUTE command is encountered, single-step mode is suspended until that command or function completes.
||Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each line. DO commands, user-defined functions, and XECUTE commands do not suspend single-step mode.
||Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each command. When a DO command, user-defined function, FOR command, or XECUTE command is encountered, single-step mode is suspended until that command or function completes.
||Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each command. DO commands, user-defined functions, FOR commands, and XECUTE commands do not suspend single-step mode.
||Can be used together with any other argument. Outputs a trace message to the trace device. This argument works only after you have set tracing to be ON with the ZBREAK /TRACE:ON command, described later. The trace device is the principal device unless you define it differently in the ZBREAK /TRACE command. If you use this argument with a breakpoint, you see the following message: TRACE: ZBREAK at label2^rou2. If you use this argument with a watchpoint, you see a trace message that names the variable being watched and the command being acted upon. In the example below, the variable a was being watched. It changed at the line test+1 in the routine test. TRACE: ZBREAK SET a=2 at test+1^test. If you include the "T" action, you must also explicitly include the "B" action as in ZBREAK *a:"TB", to have an actual break occur.
||Take no action at this breakpoint/watchpoint. The condition expression is always evaluated and determines if the execute_code is executed.
The following example establishes a watchpoint that suspends execution whenever the local variable a
is killed. No action is specified, so "B" is assumed.
The following example illustrates the above watchpoint acting on a direct mode Caché command (rather than on a command issued from within a routine). The caret (^) points to the command that caused execution to be suspended:
The following example establishes a breakpoint that suspends execution and sets single-step mode at the beginning of the line label2
The following example shows how the break would appear when the routine is run. The caret (^) indicates where execution was suspended.
label2 SET x=1
In the following example, a breakpoint at line label3
does not suspend execution, because of the "N" action. However, if x<1 when the line label3
is reached, then flag
is SET to x
ZBREAK label3^rou:"N":"x<1":"SET flag=x"
The following example establishes a watchpoint that executes the code in ^GLO whenever the value of a
changes. The double colon indicates no condition
ZBREAK *a:"N"::"XECUTE ^GLO"
The following example establishes a watchpoint that causes a trace message to display whenever the value of b
changes. The trace message will display only if trace mode has been turned on with the ZBREAK /TRACE:ON
The following example establishes a watchpoint that suspends execution in single-step mode when variable a
is set to 5.
When the break occurs in the following example, a caret (^) symbol points to the command that caused the variable a
to be set to 5.
FOR i=1:1:6 SET a=a+1
%SYS 3f0>WRITE a
You can disable either:
Disabling Specific Breakpoints and Watchpoints
You can disable a breakpoint or watchpoint by preceding the location with a minus sign. The following command disables a breakpoint previously specified for location label2
A disabled breakpoint is turned off
, but Caché remembers its definition. You can enable the disabled breakpoint by preceding the location with a plus sign. The following command enables the previously disabled breakpoint:
Disabling All Breakpoints and Watchpoints
You can disable all breakpoints or watchpoints by using the plus or minus signs without a location:
||Disable all defined breakpoints and watchpoints.
||Enable all defined breakpoints and watchpoint.
You can also delay the execution of a break/watch point for a specified number of iterations. You might have a line of code that appears within a loop that you want to break on periodically, rather than every time it is executed. To do so, establish the breakpoint as you would normally, then disable with a count following the location argument.
The following ZBREAK
command causes the breakpoint at label2
to be disabled for 100 iterations. On the 101st time this line is executed, the specified breakpoint action occurs.
ZBREAK label2^rou ; establish the breakpoint
ZBREAK -label2^rou#100 ; disable it for 100 iterations
A delayed breakpoint is not decremented when a line is repeatedly executed because it contains a FOR
You can delete individual break/watchpoints by preceding the location with a double minus sign; for example:
After you have deleted a breakpoint/watchpoint, you can only reset it by defining it again.
To delete all breakpoints, issue the command:
This command is performed automatically when a Caché process halts.
You can use single step execution to stop execution at the beginning of each line or of each command in your code. You can establish a single step breakpoint to specify actions and execution code to be executed at each step. Use the following syntax to define a single step breakpoint:
Unlike other breakpoints, ZBREAK
$ does not cause a break, because breaks occur automatically as you single-step. ZBREAK
$ lets you specify actions and execute code at each point where the debugger breaks as you step through the routine. It is especially useful in tracing executed lines or commands. For example, to trace executed lines in the application ^TEST
The "T" action specified alone (that is, without any other action code) suppresses the single step break that normally occurs automatically. (You can also suppress the single-step break by specifying the "N" action code either with or without any other action codes.)
Establish the following single-step breakpoint definition if both tracing and breaking should occur:
You can control whether or not the "T" action of the ZBREAK
command is enabled by using the following form of ZBREAK
||Enables tracing of application by performing the equivalent of: ZBREAK /TRACE:ON[:device] BREAK "L+" ZBREAK $:"T"
is used with the ALL or ON state keywords, trace messages are redirected to the specified device rather than to the principal device. If the device is not already open, Caché attempts to open it as a sequential file with WRITE and APPEND options.
When device is specified with the OFF state keyword, Caché closes the file if it is currently open.
Tracing messages are generated at breakpoints associated with a T
action. With one exception, the trace message format is as follows for all breakpoints:
The trace message format is slightly different for single step breakpoints when stepping is done by command:
is the line reference of the breakpoint and source_offset
is the 0-based offset to the location in the source line where the break has occurred.
Operating System Notes:
Trace messages to another device are supported on Windows platforms for terminal devices connected to a COM port, such as COM1:. You cannot use the console or a terminal window. You can specify a sequential file for the trace device
To send trace messages to another device on UNIX® platforms:
Log in to /dev/tty01.
Verify the device name by entering the tty command:
Issue the following command to avoid contention for the device:
$ exec sleep 50000
Return to your working window.
Start and enter Caché.
Issue your trace command:
Run your program.
If you have set breakpoints or watchpoints with the T
action, you see trace messages appear in the window connected to /dev/tty01
Trace Message Format
If you set a code breakpoint, the following message appears:
Trace: ZBREAK at label2^rou2
If you set a variable watchpoint, one of the following messages appears:
Trace: ZBREAK SET var=val at label2^rou2
Trace: ZBREAK SET var=Array Val at label2^rou2
Trace: ZBREAK KILL var at label2^rou2
is the variable being watched.
is the new value being set for that variable.
If you issue a NEW
command, you receive no trace message. However, the trace on the variable is triggered the next time you issue a SET
on the variable at the NEW
level. If a variable is passed by reference
to a routine, then that variable is still traced, even though the name has effectively changed.
Normally, pressing the interrupt key sequence (typically CTRL-C
) generates a trapable (<INTERRUPT>) error. To set interrupt processing to cause a break instead of an <INTERRUPT> error, use the following ZBREAK
command: ZBREAK /INTERRUPT:Break
This causes a break to occur when you press the INTERRUPT key even if you have disabled interrupts at the application level for the device.
If you press the INTERRUPT key during a read from the terminal, you may have to press RETURN
to display the break-mode prompt. To reset interrupt processing to generate an error rather than cause a break, issue the following command: ZBREAK /INTERRUPT:NORMAL
To display information about the current debug environment, including all currently defined break or watchpoints, issue the ZBREAK
command with no arguments.
The argumentless ZBREAK
command describes the following aspects of the debug environment:
Whether trace output specified with the "T" action in the ZBREAK
The location of all defined breakpoints, with flags describing their enabled/disabled status, action, condition and executable code
All variables for which there are watchpoints, with flags describing their enabled/disabled status, action, condition and executable code
Output from this command is displayed on the device you have defined as your debug device, which is your principal device unless you have defined the debug device differently with the ZBREAK /DEBUG command described in the Using the Debug Device
The following table describes the flags provided for each breakpoint and watchpoint:
|Identification of break/watch point
||Line in routine for breakpoint. Local variable for watchpoint.
||Flag providing information about the type of action defined in the ZBREAK command.
||Number of iterations to delay execution of a breakpoint/watchpoint defined in a ZBREAK - command.
||Condition argument set in ZBREAK command.
||Execute_code argument set in ZBREAK command.
The following table describes how to interpret the F: value in a breakpoint/watchpoint display. The F: value is a list of the applicable values in the first column.
||Breakpoint or watchpoint enabled
||Breakpoint or watchpoint disabled
||Perform a break
||Perform an "L"
||Perform an "L+"
||Perform an "S"
||Perform an "S+"
||Output a Trace Message
When you first enter Caché and use ZB
, the output is as follows:
Display When Breakpoints and Watchpoints Exist
This example shows two breakpoints and one watchpoint being defined:
%SYS>ZBREAK +3^test:::"WRITE ""IN test"""
BREAK: TRACE ON
+3^test F:EB S:5 C: E:"WRITE ""IN test"""
+5^test F:DL S:0 C: E:
a F:ET S:0 C:"a=5" E:
The first two ZBREAK
commands define a delayed breakpoint; the second two ZBREAK
commands define a disabled breakpoint; the fifth ZBREAK
command defines a watchpoint. The sixth ZBREAK
command enables trace execution. The final ZBREAK
command, with no arguments, displays information about current debug settings.
In the example, the ZBREAK
display shows that:
Tracing is ON
There is no break if CTRL-C
The output then describes the two breakpoints and one watchpoint:
The F flag for the first breakpoint equals EB
and the S flag equals 5, which means that a breakpoint will occur the fifth time the line is encountered. The E flag displays executable code, which will run before the Caché Programmer prompt for the break is displayed.
The F flag for the second breakpoint equals DL
, which means it is disabled, but if enabled will break and then single-step through each line of code following the breakpoint location.
The F flag for the watchpoint is ET
, which means the watchpoint is enabled. Since trace execution is ON, trace messages will appear on the trace device. Because no trace device was defined, the trace device will be the principal device.
The C flag means that trace is displayed only when condition
The debug device is the device where:
On Windows platforms, trace messages to another device are supported only for terminal devices connected to a COM port, such as COM1:
When you enter Caché, the debug device will automatically be set to your principal device. At any time, debugging I/O can be sent to an alternate device with the command: ZBREAK /DEBUG:"device"
There are also operating-system-specific actions that you can take.
On UNIX® systems, to cause the break to occur on the tty01 device, issue the following command:
When a break occurs, because of a CTRL-C
or to a breakpoint or watchpoint being triggered, it appears in the window connected to the device. That window becomes the active window.
If the device is not already open, an automatic OPEN is performed. If the device is already open, any existing OPEN parameters are respected.
If the device you specify is not an interactive device (such as a terminal), you may not be able to return from a break. However, the system does not enforce this restriction.
First, suppose you are debugging the simple program named test shown below. The goal is to put 1 in variable a
, 2 in variable b
, and 3 in variable c
test; Assign the values 1, 2, and 3 to the variables a, b, and c
SET c=3 KILL a WRITE "in test, at end"
However, when you run test, only variables b
hold the correct values:
in test, at end
The problem in the program is obvious: variable a
is KILLed on line 4. However, assume you need to use the debugger to determine this.
You can use the ZBREAK
command to set single-stepping through each line of code ("L" action) in the routine test. By a combination of stepping and writing the value of a
, you determine that the problem lies in line 4:
%SYS 1S1>ZBREAK ^test:"L"
%SYS 1S1>DO ^test
%SYS 3d3>WRITE a
%SYS 3d3>WRITE a
SET c=3 KILL a WRITE "in test, at end"
%SYS 3d3>WRITE a
in test, at end
%SYS 3d3>WRITE a
You can now examine that line and notice the KILL a
command. In more complex code, you might now want to single-step by command ("S" action) through that line.
If the problem occurred within a DO
, or XECUTE
command or a user-defined function, you would use the "L+" or "S+" actions to single-step through lines or commands within the lower level of code.
The Caché Debugger
flags an error in a condition or execute argument with an appropriate Caché error message.
If the error is in the execute_code
argument, the condition surrounds the execute code when the execute code is displayed before the error message. The condition special variable ($TEST
) is always set back to 1 at the end of the execution code so that the rest of the debugger processing code works properly. When control returns to the routine, the value of $TEST
within the routine is restored.
Suppose you issue the following ZBREAK
command for the example program test:
%SYS>ZBREAK test+1^test:"B":"a=5":"WRITE b"
In the program test, variable b
is not defined at line test+1, so there is an error. The error display appears as follows:
IF a=5 XECUTE "WRITE b" IF 1
If you had not defined a condition
, then an artificial true condition would be defined before and after the execution code; for example:
%SYS>IF 1 WRITE b IF 1
Caché includes three forms of the BREAK
without an argument inserted into routine code establishes a breakpoint at that location. When encountered during code execution this breakpoint suspend execution and returns to Programmer Mode.
with a letter string argument establishes or deletes breakpoints at that enable stepping through code on a line-by-line or command-by-command basis.
command with an integer argument enables or disables CTRL-C
user interrupts. (Refer to the BREAK
command for further details.)
To suspend a running routine and return the process to Programmer Mode, enter an argumentless BREAK
into your routine at points where you want execution to temporarily stop.
When Caché encounters a BREAK
, it takes the following steps:
Suspends the running routine
Returns the process to Programmer Mode
You can now issue ObjectScript commands, modify data, and execute further routines or subroutines, even those with errors or additional BREAKs.
To resume execution at the point at which the routine was suspended, issue an argumentless GOTO
You may find it useful to specify a postconditional on an argumentless BREAK
command so that you can rerun the same code simply by setting the postconditional variable rather than having to change the routine. For example, you may have the following line in a routine:
You can then set the variable debug
to suspend the routine and return the job to Programmer Mode or clear the variable debug
to continue running the routine.
You do not have to place argumentless BREAK
commands at every location where you want to suspend your routine. Caché provides several argument options that allow you to step through the execution of the code. You can step through the code by single steps (BREAK S
) or by command line (BREAK L
). For a full list of these letter code arguments, see the BREAK
When you enter Programmer Mode, the break state is not stacked. Thus you can change the break state and the new state remains in effect when you issue an argumentless GOTO
to return to the executing routine.
Caché stacks the break state whenever a DO
, or user-defined function is entered. If you choose BREAK "C"
to turn off breaking, the system restores the break state at the end of the DO
, or user-defined function. Otherwise, Caché ignores the stacked state.
Thus if you enable breaking at a low subroutine level, breaking continues after the routine returns to a higher subroutine level. In contrast, if you disable breaking at a low subroutine level that was in effect at a higher level, breaking resumes when you return to that higher level. You can use BREAK "C-"
to disable breaking at all levels.
You can use BREAK L-
to disable breaking at the current level but enables line breaking at the previous level. You can use BREAK S-
to disable breaking at the current level but enables single-step breaking at the previous level.
Shutting Off Debugging
To remove all debugging that has been established for a process, use the BREAK "OFF"
command. This command removes all breakpoints and watchpoints and turns off stepping at all program stack levels. It also removes the association with the debug and trace devices, but does not close them.
Invoking BREAK "OFF"
is equivalent to issuing the following set of commands:
When a BREAK
command suspends execution of a routine or when an error occurs, the program stack retains some stacked information. When this occurs in Programmer Mode, a brief summary of this information is displayed before the Programmer Mode prompt ( > ). Such messages take the form: 5d3>, where:
||Indicates there are five stack levels. A stack level can be caused by a DO, FOR, XECUTE, NEW, user-defined function call, error state, or break state.
||Indicates that the last item stacked is a DO.
||Indicates there are 3 NEW states, parameter passing, or user-defined functions on the stack. This value is a zero if no NEW commands, parameter passing, or user-defined functions are stacked.
Prompts you can see in such messages are listed in the following table.
Stack Error Codes in Programmer Mode
In the following example, command line statements are shown with their resulting Programmer Mode prompts when adding stack frames:
USER 2N1>XECUTE "NEW WRITE 123 BREAK"
You can unwind the program stack using QUIT 1
. The following is an example of Programmer Mode prompts when unwinding the stack:
USER 6f0>QUIT 1 /* an error occurred in a FOR loop. */
USER 5x0>QUIT 1 /* the FOR loop was in code invoked by XECUTE. */
USER 4f0>QUIT 1 /* the XECUTE was in a FOR loop. */
USER 3f0>QUIT 1 /* that FOR loop was nested inside another FOR loop. */
USER 2d0>QUIT 1 /* the DO command was used to execute the program. */
USER 1S0>QUIT 1 /* sign on state. */
When entering Programmer Mode after a BREAK
or an error, Caché keeps track of the location of the command that caused the BREAK
or error. Later, you can resume execution at the next command simply by entering an argumentless GOTO
in Programmer Mode:
By typing a GOTO
with an argument, you can resume execution at the beginning of another line in the same routine with the break or error, as follows:
You can also resume execution at the beginning of a line in a different routine:
Alternatively, you may clear the program stack with an argumentless QUIT
The following routines are used in the examples below.
MAIN ; 03 Jan 99 11:40 AM
DO ^SUB1 WRITE !,"sum=",sum
SUB1 ; 03 Jan 99 11:42 AM
With BREAK "L"
, breaking does not occur in the routine SUB1.
DO ^SUB1 WRITE !,"sum=",sum
"L+", breaking also occurs in the routine SUB1.
DO ^SUB1 Write !,"sum=",sum
The argumentless NEW
command effectively saves all symbols in the symbol table so you can proceed with an empty symbol table. You may find this command particularly valuable when you are in Programmer Mode after an error or BREAK
To run other routines without disturbing the symbol table, issue an argumentless NEW
command in Programmer Mode. The system then:
The 5B1> prompt indicates that the system has stacked the Programmer Mode entered through a BREAK
. The 1 indicates that a NEW
command has stacked variable information, which you can remove by issuing a QUIT 1
. When you wish to resume execution, issue a QUIT 1
to restore the old symbol table, and a GOTO
to resume execution.
Whenever you use a NEW
command, parameter passing, or user-defined function, the system places information on the stack indicating that later an explicit or implicit QUIT
at the current subroutine or XECUTE level should delete certain variables and restore the value of others.
In Programmer Mode, you may find it useful to know if any NEW
commands, parameter passing, or user-defined functions have been executed (thus stacking some variables), and if so, how far back on the stack this information resides.
In Programmer Mode, you can remove all items from the program stack by entering an argumentless QUIT
To remove only a couple of items from the program stack (for example, to leave a currently executing subroutine and return to a previous DO
level), use QUIT
with an integer argument. QUIT 1 removes the last item on the program stack, QUIT 3 removes the last three items, and so forth, as illustrated below:
Caché displays error messages within angle brackets, as in <ERROR>, followed by a reference to the line that was executing at the time of the error and by the routine. A caret (^) separates the line reference and routine. Also displayed is the intermediate code line with a caret character under the first character of the command executing when the error occurred. For example:
SET x=y+3 DO ^ABC
This error message indicates an <UNDEFINED> error (that refers to the variable y
) in line label+3 of routine rou. At this point, this message is also the value of the special variable $ZERROR
You can use the %STACK utility to:
You execute %STACK by entering the following command:
As shown in this example, the %STACK utility displays the current process stack without variables.
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
Under the current execution stack display, %STACK prompts you for a stack display action. You can get help by entering a question mark (?) at the Stack Display Action
Depending on what you enter at the Stack Display Action
prompt, you can display the current process execution stack in four forms:
Without variables, by entering *F
With a specific variable, by entering *V
With all variables, by entering *P
With all variables, preceded by a list of process state variables, by entering *A
Displaying the Stack without Variables
The process execution stack without variables appears when you first enter the %STACK utility or when you type the stack action *F.
Displaying the Stack with a Specific Variable
Enter *V at the Stack Display Action prompt, followed by the name of the variable you want to track through the stack. In the following example, the variable e
is being tracked and the display is sent to the screen by pressing RETURN
at the Device:
Stack Display Action: *V
Display on Device: <RETURN>
Displaying the Stack with All Defined Variables
Enter *P to see the process execution stack together with the current values of all defined variables.
Displaying the Stack with All Variables, including State Variables
You can print all possible reports to screen, file or printer by entering *A at the Stack Display Action prompt. This report prints the following:
Each item on the stack is called a frame
. The following table describes the information provided for each frame.
%STACK Utility Information
||Identifies the level within the stack. The oldest item on the stack is number 1. Frames without an associated level number share the level that first appears above them.
||Identifies the type of frame on the stack, which can be: DIRECT BREAK: A BREAK command was encountered that caused a return to direct mode. DIRECT CALLIN: A Caché process was initiated from an application outside of Caché, using the Caché call-in interface. DIRECT ERROR: An error was encountered that caused a return to direct mode. DO: A DO command was executed. ERROR TRAP: If a routine sets $ZTRAP, this frame identifies the location where an error will cause execution to continue. FOR: A FOR command was executed. NEW: A NEW command was executed. If the NEW command had arguments, they are shown. SIGN ON: Execution of the Caché process was initiated. XECUTE: An XECUTE command was executed. $$EXTFUNC: A user-defined function was executed.
||Identifies the ObjectScript source line associated with the frame, if available, in the format label+offset^routine.
||Shows the source code for the line, if it is available. If the source is too long to display in the area provided, horizontal scrolling is available. If the device is line- oriented, the source wraps around and continued lines are preceded with ....
The following table shows whether level, line, and source values are available for each frame type. A "No" under Level indicates that the level number is not incremented and no level number appears in the display.
Frame Types and Values Available
|DIRECT CALL IN
||No, but the new $ZTRAP value is shown.
||Shows the form of the NEW (inclusive or exclusive) and the variables affected.
||Shows the formal parameter list. If a parameter is passed by reference, shows what other variables point to the same memory location.
|* The LINE value is blank if these are invoked from Programmer Mode.
Moving through %STACK Display
If a %STACK display fills more than one screen, you see the prompt -- more --
in the bottom left corner of the screen. At the last page, you see the prompt -- fini --
. Type ? to see key presses you use to maneuver through the %STACK display.
- - - Filter Help - - -
<space> Display next page.
<return> Display one more line.
T Return to the beginning of the output.
B Back up one page (or many if arg>1).
R Redraw the current page.
/text Search for \qtext\q after the current page.
A View all the remaining text.
? Display this screen
# specify an argument for B, L, or W actions.
L set the page length to the current argument.
W set the page width to the current argument.
For the B, L and W commands, you enter a numeric argument before the command letter. For instance, enter 2B to move back two pages, or enter 20L to set the page length to 20 lines.
Be sure to set your page length to the number of lines which are actually displayed; otherwise, when you do a page up or down, some lines may not be visible. The default page length is 23.
Displaying Variables at Specific Stack Level
To see the variables that exist at a given stack frame level, enter ?# at the Stack Display Action
prompt, where # is the stack frame level. The following example shows the display if you request the variables at level 1.
Stack Display Action: ?1
The following Variables are defined for Stack Level: 1
Stack Display Action:
Displaying Stack Levels with Variables
You can display the variables defined at all stack levels by entering ?? at the Stack Display Action
prompt. The following example shows a sample display if you select this action.
Stack Display Action: ??
Now loading variable information ... 19
Base Stack Level: 5
Base Stack Level: 3
A B C D
Base Stack Level: 1
Stack Display Action:
Displaying Process State Variables
To display the process state variables, such as $IO
, enter *S at the Stack Display Action prompt. You will see these defined variables (Process State Intrinsics) as listed in the following table:
|Process State Intrinsics
||$DEVICE special variable
|$EC = ,M9,
||$ECODE special variable
|$ES = 4
||$ESTACK special variable
||$ETRAP special variable
|$H = 64700,50668
||$HOROLOG special variable
|$I = |TRM|:|5008
||$IO special variable
|$J = 5008
||$JOB special variable
|$K = $c(13)
||$KEY special variable
|$P = |TRM|:|5008
||$PRINCIPAL special variable
|$Roles = %All
||$ROLES special variable
|$S = 268315992
||$STORAGE special variable
|$T = 0
||$TEST special variable
|$TL = 0
||$TLEVEL special variable
|$USERNAME = glenn
||$USERNAME special variable
|$X = 0
||$X special variable
|$Y = 17
||$Y special variable
|$ZA = 0
||$ZA special variable
|$ZB = $c(13)
||$ZB special variable
|$ZC = 0
||$ZCHILD special variable
|$ZE = <DIVIDE>
||$ZERROR special variable
|$ZJ = 5
||$ZJOB special variable
|$ZM = RY\Latin1\K\UTF8\
||$ZMODE special variable
|$ZP = 0
||$ZPARENT special variable
|$ZR = ^||a
||$ZREFERENCE special variable
|$ZS = 262144
||$ZSTORAGE special variable
||$ZTRAP special variable
|$ZTS = 64700,68668.58
||$ZTIMESTAMP special variable
|$ZU(5) = USER
|$ZU(12) = c:\intersystems\cache\mgr\
|$ZU(18) = 0
|$ZU(20) = USER
|$ZU(23,1) = 5
|$ZU(34) = 0
|$ZU(39) = USER
|$ZU(55) = 0
|$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
|$ZU(67,10,$J) = 1
|$ZU(67,11,$J) = glenn
|$ZU(67,12,$J) = TRM:
|$ZU(67,15,$J) = 127.0.0.1
|$ZU(67,4,$J) = 0^0^0
|$ZU(67,5,$J) = %STACK
|$ZU(67,6,$J) = USER
|$ZU(67,7,$J) = |TRM|:|5008
|$ZU(67,8,$J) = 923
|$ZU(67,9,$J) = 46
|$ZU(68,1) = 0
| $ZU(68,21) = 0
|$ZU(68,25) = 0
|$ZU(68,27) = 1
|$ZU(68,32) = 0
|$ZU(68,34) = 1
|$ZU(68,36) = 0
|$ZU(68,40) = 0
|$ZU(68,41) = 1
|$ZU(68,43) = 0
|$ZU(68,5) = 1
| $ZU(68,6) = 0
| $ZU(68,7) = 0
|$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 special variable
Printing the Stack and/or Variables
When you select the following actions, you can choose the output device:
There are also other tools available to aid in the debugging process. These include:
The error trap utilities, %ETN and %ERN, help in error analysis by storing variables and recording other pertinent information about an error.
%ETN Application Error Trap
You may find it convenient to set the error trap to execute the utility %ETN
on an application error. This utility saves valuable information about the job at the time of the error, such as the execution stack and the value of variables. This information is saved in the application error log, which you can display with the %ERN
utility or view in the Management Portal
on the View Application Error Log
page (System Operation
, System Logs
, Application Error Log
Use the following code to set the error trap to this utility:
In a procedure, you cannot set $ZTRAP
to an external routine. Because of this restriction, you cannot use ^%ETN
in procedures (including class methods that are procedures). However, you can set $ZTRAP
to a local label that calls %ETN
When an error occurs and you call the %ETN utility, you see a message similar to the following message:
Error has occurred: <SYNTAX> at 10:30 AM
ends with a HALT
command (terminates the process) you may want to set the %ETN
error trap only if the routine is used in Application Mode. When an error occurs in Programmer Mode, it may be useful for the error to be displayed on the terminal and go into the debugger prompt to allow for immediate analysis of the error. The following code sets an error trap only if Caché is in Application Mode:
%ERN Application Error Report
In the following code, a ZLOAD
of the routine REPORT is issued to illustrate that by loading all of the variables with *LOAD
and then loading the routine, you can recreate the state of the job when the error occurred except that the program stack, which records information about DO
s, etc., is empty.
For Date: 4/30/2018 3 Errors
1) "<DIVIDE>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)
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)
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)
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)
%DAT="Apr 30 2018"
%DAT="Apr 30 2018"
XY="SET $X=250 WRITE *27,*91,DY+1,*59,DX+1,*72 SET $X=DX,$Y=DY"