This topic describes techniques for testing and debugging Object Script code. InterSystems IRIS® gives you two ways to debug code:
InterSystems IRIS includes the ability to suspend a routine and enter a shell that supports full debugging capabilities, as described in this topic. InterSystems IRIS also includes a secure debug shell, which has the advantage of ensuring that users are prevented from exceeding or circumventing their assigned privileges.
Secure Debug Shell
The secure debug shell helps better control access to sensitive data. It is an environment that allows users to perform basic debugging, such as stepping and displaying variables, but does not allow them to do anything that changes the execution path or results of a routine. This protects against access that can lead to issues such as manipulation, malicious role escalation, and the injection of code to run with higher privileges.
By default, users at the debug prompt maintain their current level of privileges. To enable the secure shell for the debug prompt and thereby restrict the commands that the user may issue, you must enable the secure debug shell for that user.
If enabled for the current user, the secure debug shell starts when a BREAK command is executed, a breakpoint or watchpoint is encountered, or an uncaught error is issued.
Within the secure debug shell, the user cannot invoke:
-
Any command that can modify a variable.
-
Any function that can modify a variable.
-
Any command that can call other routines.
-
Any command that affects the flow of the routine or the environment.
Within the secure debug shell, when a user attempts to invoke a restricted command or function, InterSystems IRIS throws a <COMMAND> or <FUNCTION> error, respectively.
Restricted Commands and Functions
This section lists the restricted activities within the secure debug shell:
Restricted ObjectScript Commands
The following are the restricted ObjectScript commands for the secure debug shell:
Restricted ObjectScript Functions
The following are the restricted ObjectScript functions for the secure debug shell:
-
$CLASSMETHOD
-
$COMPILE
-
$DATA(,var) — two-argument version only
-
$INCREMENT
-
$METHOD
-
$ORDER(,,var) — three-argument version only
-
$PROPERTY
-
$QUERY(,,var) — three-argument version only
-
$XECUTE
-
$ZF
-
$ZSEEK
-
any extrinsic function
Restricted Object Constructions
No method or property references are allowed. Property references are restricted because they could invoke a propertyGet method. Some examples of the object method and property syntax constructions that are restricted are:
Note:
Even without passing a variable by reference, a method can modify public variables. Since a property reference could invoke a propGet method, no property access is allowed.
Debugging with the ObjectScript Debugger
The ObjectScript 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 InterSystems IRIS 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 InterSystems IRIS applications to be debugged without disturbing the application’s terminal I/O.
Using Breakpoints and Watchpoints
The ObjectScript Debugger provides two ways to interrupt program execution:
A breakpoint is a location in an InterSystems IRIS routine that you specify with the ZBREAK command. When routine execution reaches that line, InterSystems IRIS 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.
Syntax
ZBREAK location[:action:condition:execute_code]
where:
Argument |
Description |
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 — A boolean expression, enclosed in curly braces or quotes, that is evaluated when the breakpoint/watchpoint is triggered.
-
When condition is true (1), the action is carried out.
-
When condition is false, the action is not carried out and the code in execute_code is not executed.
If condition is not specified, the default is true. |
execute_code |
Optional — Specifies ObjectScript code to be executed if condition is true. If the code is a literal, it must be surrounded by curly braces or quotation marks. 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. |
Note:
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, InterSystems IRIS 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:
Value |
Break Location |
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:
Value |
Break Location |
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:
-
When the local variable is created
-
When a SET command changes the value of the local variable
-
When a KILL command deletes the local variable
Variable names are preceded by an asterisk, as in *a.
If you specify an array-variable name, the ObjectScript 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:
System Variable |
Trigger Event |
$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. Then displays the Terminal prompt and allows interaction. Execution resumes with 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 ObjectScript command (rather than on a command issued from within a routine). The caret (^) points to the command that caused execution to be suspended:
USER>KILL a
KILL a
^
<BREAK>
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
^
<BREAK>label2^rou
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.
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 command.
ZBREAK *b:"T"
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
^
<BREAK>
test+3^test
USER 3f0>WRITE a
5
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 InterSystems IRIS 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:
Sign |
Description |
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
Important:
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:
ZBREAK /CLEAR
This command is performed automatically when an InterSystems IRIS 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:
USER>ZBREAK /TRACE:ON
USER>BREAK "L+"
USER>ZBREAK $:"T"
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:
State |
Description |
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, InterSystems IRIS attempts to open it as a sequential file with WRITE and APPEND options.
When device is specified with the OFF state keyword, InterSystems IRIS closes the file if it is currently open.
Note:
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:
-
Windows — 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
-
UNIX® — To send trace messages to another device on UNIX® platforms:
-
Log in to /dev/tty01.
-
Verify the device name by entering the tty command:
$ tty
/dev/tty01
-
Issue the following command to avoid contention for the device:
$ exec sleep 50000
-
Return to your working window.
-
Start and enter InterSystems IRIS.
-
Issue your trace command:
ZBREAK /T:ON:"/dev/tty01"
-
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
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:
-
Whether CTRL-C causes a break
-
Whether trace output specified with the "T" action in the ZBREAK command displays
-
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 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 InterSystems IRIS and use ZB, the output is as follows:
USER>ZBREAK
BREAK:
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"
USER>ZBREAK /TRACE:ON
USER>ZBREAK
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:
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 Terminal 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 is true.
Using the Debug Device
The debug device is the device where:
Note:
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 InterSystems IRIS, 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".
Note:
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.
Important:
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.
ObjectScript 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"
QUIT
However, when you run test, only variables b and c hold the correct values:
USER>DO ^test
in test, at end
USER>WRITE
b=2
c=3
USER>
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:
USER>NEW
USER 1S1>ZBREAK
BREAK
No breakpoints
No watchpoints
USER 1S1>ZBREAK ^test:"L"
USER 1S1>DO ^test
SET a=1
^
<BREAK>test+1^test
USER 3d3>WRITE a
<UNDEFINED>^test
USER 3d3>GOTO
SET b=2
^
<BREAK>test+2^test
USER 3d3>WRITE a
1
USER 3d3>GOTO
SET c=3 KILL a WRITE "in test, at end"
^
<BREAK>test+3^test
USER 3d3>WRITE a
1
USER 3d3>GOTO
in test, at end
QUIT
^
<BREAK>test+4^test
USER 3d3>WRITE a
WRITE a
^
<UNDEFINED>^test
USER 3d3>GOTO
USER 1S1>
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 ObjectScript Debugger Errors
The ObjectScript Debugger flags an error in a condition or execute argument with an appropriate InterSystems IRIS 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 a=5 XECUTE "WRITE b" IF 1
^
<UNDEFINED>test+1^test
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
InterSystems IRIS includes three forms of the BREAK command:
-
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 the Terminal prompt.
-
BREAK 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.
-
The BREAK command with an integer argument enables or disables CTRL-C user interrupts. (Refer to the BREAK command for further details.)
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 InterSystems IRIS encounters a BREAK, it takes the following steps:
-
Suspends the running routine
-
Returns the process to the Terminal prompt. When debugging an application that uses I/O redirection of the principal device, redirection will be turned off at the debug prompt so output from a debug command will be shown on the Terminal.
You can now issue ObjectScript commands, modify data, and execute further routines or subroutines, even those with errors or additional BREAKs. If you issue an ObjectScript command from the debug Terminal prompt, this command is immediately executed. It is not inserted into the running routine. This command execution is the same behavior as the ordinary Terminal prompt, with one difference: a command proceeded by a Tab character is executed from the debug Terminal prompt; a command proceeded by a Tab character is not executed from the ordinary Terminal prompt.
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:
CHECK BREAK:$DATA(debug)
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, see Command Postconditional Expressions.
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. InterSystems IRIS 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 return to the executing routine.
InterSystems IRIS 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, InterSystems IRIS 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:
ZBREAK /CLEAR
ZBREAK /TRACE:OFF
ZBREAK /DEBUG:""
ZBREAK /ERRORTRAP:ON
BREAK "C-"
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:
Character |
Description |
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 |
x |
XECUTE |
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:
USER>NEW
USER 1S1>NEW
USER 2N1>XECUTE "NEW WRITE 123 BREAK"
<BREAK>
USER 4x1>NEW
USER 5B1>BREAK
<BREAK>
USER 6N2>
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. */
USER>
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, InterSystems IRIS 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:
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 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
QUIT
SUB1 ; 03 Jan 2019 11:42 AM
SET sum=x+y+z
QUIT
With BREAK "L", breaking does not occur in the routine 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>
With BREAK "L+", breaking also occurs in the routine 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>
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 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:
USER 4d0>NEW
USER 5B1>DO ^%T
3:49 PM
USER 5B1>QUIT 1
USER 4d0>GOTO
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:
InterSystems IRIS Error Messages
InterSystems IRIS 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
^
<UNDEFINED>label+3^rou
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.