Using Caché ObjectScript
Command-line Routine Debugging
[Home] [Back] [Next]
InterSystems: The power behind what matters   

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:
Debugging with the Caché Debugger
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:
Using Breakpoints and Watchpoints
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 or KILL 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.
Establishing Breakpoints and Watchpoints
You use the ZBREAK command to establish breakpoints and watchpoints.
ZBREAK location[:action:condition:execute_code]
location 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.
action 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.
condition 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.
execute_code 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.
Using ZBREAK 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:
label^rou Break before the line at the line label label in the routine rou.
label+3^rou Break before the third line after the line label label in routine rou.
+3^rou Break before the third line in routine rou.
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:
label Break before the line label at label.
label+3 Break before the third line after label.
+3 Break before the third line.
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:
$ZERROR Triggered whenever an error occurs, before invoking the error trap.
$ZTRAP Triggered whenever an error trap is set or cleared.
$IO Triggered whenever explicitly SET.
Action Argument Values
The following table describes the values you can use for the ZBREAK action argument.
Argument Description
"B" 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. It then displays the Terminal prompt and allows interaction. Execution resumes when you issue an argumentless GOTO command.
"L" 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.
"L+" 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.
"S" 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.
"S+" 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.
"T" 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.
"N" Take no action at this breakpoint/watchpoint. The condition expression is always evaluated and determines if the execute_code is executed.
ZBREAK Examples
The following example establishes a watchpoint that suspends execution whenever the local variable a is killed. No action is specified, so "B" is assumed.
ZBREAK *a::"'$DATA(a)"
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:
USER 1s0>
The following example establishes a breakpoint that suspends execution and sets single-step mode at the beginning of the line label2^rou.
ZBREAK label2^rou:"L"
The following example shows how the break would appear when the routine is run. The caret (^) indicates where execution was suspended.
USER>DO ^rou
label2 SET x=1
USER 2d0>
In the following example, a breakpoint at line label3^rou does not suspend execution, because of the "N" action. However, if x<1 when the line label3^rou 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 argument.
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 command.
The following example establishes a watchpoint that suspends execution in single-step mode when variable a is set to 5.
ZBREAK *a:"S":"a=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.
USER>DO ^test
FOR i=1:1:6 SET a=a+1
Disabling Breakpoints and Watchpoints
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^rou:
ZBREAK -label2^rou
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:
ZBREAK +label2^rou
Disabling All Breakpoints and Watchpoints
You can disable all breakpoints or watchpoints by using the plus or minus signs without a location:
ZBREAK - Disable all defined breakpoints and watchpoints.
ZBREAK + Enable all defined breakpoints and watchpoint.
Delaying Execution of Breakpoints and Watchpoints
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^rou 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 command.
Deleting Breakpoints and Watchpoints
You can delete individual break/watchpoints by preceding the location with a double minus sign; for example:
ZBREAK --label2^rou
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.
Single-step Breakpoint Actions
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:
ZBREAK $:action[:condition:execute_code]
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:
Tracing Execution
You can control whether or not the "T" action of the ZBREAK command is enabled by using the following form of ZBREAK:
ZBREAK /TRACE:state[:device]
where state can be:
ON Enables tracing.
OFF Disables tracing.
ALL Enables tracing of application by performing the equivalent of: ZBREAK /TRACE:ON[:device] BREAK "L+" ZBREAK $:"T"
When device 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.
ZBREAK /TRACE:OFF does not delete or disable the single-step breakpoint definition set up by ZBREAK /TRACE:ALL, nor does it clear the “L+” single stepping set up by ZBREAK /TRACE:ALL. You must also issue the commands ZBREAK --$ and BREAK "C" to remove the single stepping; alternatively, you can use the single command BREAK "OFF" to turn off all debugging for the process.
Tracing messages are generated at breakpoints associated with a “T” action. With one exception, the trace message format is as follows for all breakpoints:
Trace: ZBREAK at line_reference
where line_reference is the line reference of the breakpoint.
The trace message format is slightly different for single step breakpoints when stepping is done by command:
Trace: ZBREAK at line_reference source_offset
where line_reference 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 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
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 or KILL 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.
INTERRUPT Keypress and Break
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
Displaying Information About the Current Debug Environment
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:
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 section.
The following table describes the flags provided for each breakpoint and watchpoint:
Display Section Meaning
Identification of break/watch point Line in routine for breakpoint. Local variable for watchpoint.
F: Flag providing information about the type of action defined in the ZBREAK command.
S: Number of iterations to delay execution of a breakpoint/watchpoint defined in a ZBREAK - command.
C: Condition argument set in ZBREAK command.
E: 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.
Value Meaning
E Breakpoint or watchpoint enabled
D Breakpoint or watchpoint disabled
B Perform a break
L Perform an "L"
L+ Perform an "L+"
S Perform an "S"
S+ Perform an "S+"
T Output a Trace Message
Default Display
When you first enter Caché and use ZB, the output is as follows:
No breakpoints
No watchpoints
This means:
Display When Breakpoints and Watchpoints Exist
This example shows two breakpoints and one watchpoint being defined:
USER>ZBREAK +3^test:::"WRITE ""IN test"""
USER>ZBREAK -+3^test#5
USER>ZBREAK +5^test:"L"
USER>ZBREAK -+5^test
USER>ZBREAK *a:"T":"a=5"
+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:
The output then describes the two breakpoints and one watchpoint:
Using the Debug Device
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:
ZBREAK /D:"/dev/tty01/"
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.
Caché Debugger Example
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 a=1
 SET b=2
 SET c=3 KILL a WRITE "in test, at end"
However, when you run test, only variables b and c hold the correct values:
USER>DO ^test
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:
No breakpoints
No watchpoints
USER 1S1>ZBREAK ^test:"L"
USER 1S1>DO ^test 
SET a=1
SET b=2
SET c=3 KILL a WRITE "in test, at end"
in test, at end
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, FOR, 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.
Understanding Caché Debugger Errors
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:
USER>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 you had not defined a condition, then an artificial true condition would be defined before and after the execution code; for example:
Debugging With BREAK
Caché includes three forms of the BREAK command:
Using Argumentless BREAK to Suspend Routine Execution
To suspend a running routine and return the process to the Terminal prompt, 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:
  1. Suspends the running routine
  2. Returns the process to the Terminal prompt. From the Terminal prompt you can 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 command.
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 the Terminal prompt or clear the variable debug to continue running the routine.
For further details, refer to Command Postconditional Expressions in this manual.
Using Argumented BREAK to Suspend Routine Execution
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 command.
One difference between BREAK “S” and BREAK “L” is that many command lines consist of more than one step. This is not always obvious. For example, the following are all one line (and one ObjectScript command), but each is parsed as two steps: SET x=1,y=2, KILL x,y, WRITE “hello”,!, IF x=1,y=2.
Both BREAK “S” and BREAK “L” ignore label lines, comments, and TRY statements (though both break at the closing curly brace of a TRY block). BREAK “S” breaks at a CATCH statement (if the CATCH block is entered); BREAK “L” does not.
When a BREAK returns the process to the Terminal prompt, 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 resume the executing routine.
Caché stacks the break state whenever a DO, XECUTE, FOR, 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, XECUTE, FOR, 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+” or BREAK “S+” to enable breaking within a DO, XECUTE, FOR, or a user-defined function.
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:
Terminal Prompt Shows Program Stack Information
When a BREAK command suspends execution of a routine or when an error occurs, the program stack retains some stacked information. When this occurs, a brief summary of this information is displayed as part of the Terminal prompt ( namespace> ). For example, this information might take the form: USER 5d3>, where:
5 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.
d Indicates that the last item stacked is a DO.
3 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.
Terminal prompt letter codes are listed in the following table.
Stack Error Codes at the Terminal Prompt
Prompt Definition
d DO
e user-defined function
f FOR loop
B BREAK state
E Error state
N NEW state
S Sign-on state
In the following example, command line statements are shown with their resulting Terminal prompts when adding stack frames:
You can unwind the program stack using QUIT 1. The following is an example of Terminal 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. */
FOR Loop and WHILE Loop
You can use either a FOR or a WHILE to perform the same operation: loop until an event (usually a counter increment) causes execution to break out of the loop. However, which loop construct you use has consequences for performing single-step (BREAK "S+" or BREAK "L+") debugging on the code module.
A FOR loop pushes a new level onto the stack. A WHILE loop does not change the stack level. When debugging a FOR loop, popping the stack from within the FOR loop (using BREAK "C" GOTO or QUIT 1) allows you to continue single-step debugging with the command immediately following the end of the FOR command construct. When debugging a WHILE loop, issuing a using BREAK "C" GOTO or QUIT 1 does not pop the stack, and therefore single-step debugging does not continue following the end of the WHILE command. The remaining code executes without breaking.
Resuming Execution after a BREAK or an Error
When returned to the Terminal prompt 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 at the Terminal prompt:
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:
USER 4f0>GOTO label3
You can also resume execution at the beginning of a line in a different routine:
USER 4f0>GOTO label3^rou
Alternatively, you may clear the program stack with an argumentless QUIT command:
Sample Dialogs
The following routines are used in the examples below.
MAIN ; 03 Jan 2019 11:40 AM
 SET x=1,y=6,z=8
 DO SUB1 WRITE !,"sum=",sum
SUB1 ; 03 Jan 2019 11:42 AM
 SET sum=x+y+z
With BREAK "L", breaking does not occur in the routine SUB1.
SET x=1,y=6,z=8
DO ^SUB1 WRITE !,"sum=",sum
With BREAK "L+", breaking also occurs in the routine SUB1.
SET x=1,y=6,z=8
DO ^SUB1 WRITE !,"sum=",sum
SET sum=x+y+z
The NEW Command at the Terminal Prompt
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 at the Terminal prompt after an error or BREAK.
To run other routines without disturbing the symbol table, issue an argumentless NEW command at the Terminal prompt. The system then:
For example:
3:49 PM
The 5B1> prompt indicates that the system has stacked the current frame 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.
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.
The QUIT Command at the Terminal Prompt
From the Terminal prompt you can remove all items from the program stack by entering an argumentless QUIT command:
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:
USER 6d0>
Caché Error Messages
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.
Using %STACK to Display the Stack
You can use the %STACK utility to:
Running %STACK
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 this prompt. You can exit %STACK by pressing the Return key at this prompt.
Displaying the Process Execution Stack
Depending on what you enter at the Stack Display Action prompt, you can display the current process execution stack in four forms:
%STACK then displays the Display on Device prompt, enabling you to specify where you want this information to go. Press the Return key to display this information to the current device.
Displaying the Stack without Variables
The process execution stack without variables appears when you first enter the %STACK utility or when you type *F at the Stack Display Action prompt.
Displaying the Stack with a Specific Variable
Enter *V at the Stack Display Action prompt. This will prompt you for the name(s) of the local variable(s) you want to track through the stack. Specify a single variable or a comma-separated list of variables. It returns the names and values of all local variables. In the following example, the variable e is being tracked and the display is sent to the Terminal by pressing Return
Stack Display Action: *V 
Now loading variable information ...   2  done.
Variable(s): e
Display on 
Device: <RETURN>
Displaying the Stack with All Defined Variables
Enter *P at the Stack Display Action prompt to see the process execution stack together with the current values of all defined local variables.
Displaying the Stack with All Variables, including State Variables
Enter *A at the Stack Display Action prompt to display all possible reports. Reports are issued in the following order:
Understanding the Stack Display
Each item on the stack is called a frame. The following table describes the information provided for each frame.
%STACK Utility Information
Heading Description
Level 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.
Type 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.
Line Identifies the ObjectScript source line associated with the frame, if available, in the format label+offset^routine.
Source 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
Frame Type Level Line Source
DO Yes Yes* Yes
ERROR TRAP No No No, but the new $ZTRAP value is shown.
FOR No Yes Yes
NEW No No Shows the form of the NEW (inclusive or exclusive) and the variables affected.
PARAMETER No No Shows the formal parameter list. If a parameter is passed by reference, shows what other variables point to the same memory location.
XECUTE Yes Yes* Yes
$$EXTFUNC Yes Yes* Yes
* The LINE value is blank if these are invoked from the Terminal prompt.
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. 
Q Quit. 
? 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.
You enter any of the commands listed above whenever you see the “-- more --” or “-- fini --” prompts.
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
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 Documentation
$D = $DEVICE special variable
$EC = ,M9, $ECODE special variable
$ES = 4 $ESTACK special variable
$ET = $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
$ZT = $ZTRAP special variable
$ZTS = 64700,68668.58 $ZTIMESTAMP special variable
$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  
$ZU(67,10,$J) = 1 JobType
$ZU(67,11,$J) = glenn UserName
$ZU(67,12,$J) = TRM: ClientNodeName
$ZU(67,13,$J) = ClientExecutableName
$ZU(67,14,$J) = CSPSessionID
$ZU(67,15,$J) = ClientIPAddress
$ZU(67,4,$J) = 0^0^0 State
$ZU(67,5,$J) = %STACK Routine
$ZU(67,6,$J) = USER NameSpace
$ZU(67,7,$J) = |TRM|:|5008 CurrentDevice
$ZU(67,8,$J) = 923 LinesExecuted
$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  
$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:
Other Debugging Tools
There are also other tools available to aid in the debugging process. These include:
Displaying References to an Object with $SYSTEM.OBJ.ShowReferences
To display all variables in the process symbol table that contain a reference to a given object, use the ShowReferences(oref) method of the %SYSTEM.OBJ class. The oref is the OREF (object reference) for the given object. For details on OREFs, see the section OREF Basics in the “Working with Registered Objects” chapter of Using Caché Objects.
Error Trap Utilities
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
Because %ETN 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 at the Terminal prompt, 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:
SET $ZTRAP=$SELECT($ZJ#2:"",1:"^%ETN")
%ERN Application Error Report
The %ERN utility examines application errors recorded by the %ETN error trap utility. For information on using %ERN, refer to Using %ERN to View Application Error Logs in the “Error Processing” chapter of this manual.
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 DOs, etc., is empty.

For Date: 4/30/2018   3 Errors

Error: ?L

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)
               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)

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)

Variable: %DAT
  %DAT="Apr 30 2018" 

Variable: TYPE

Variable: *LOAD


%DAT="Apr 30 2018"
XY="SET $X=250 WRITE *27,*91,DY+1,*59,DX+1,*72 SET $X=DX,$Y=DY"

Send us comments on this page
Copyright © 1997-2019 InterSystems Corporation, Cambridge, MA