Again, before giving our views, this is what the book teaches us :
The debug facility permits interactively controlled execution of a program.
Changing the TRACE action to one with a prefix ? (for example, TRACE ?A) turns on interactive debug and indicates to the user that interactive debug is active. Further TRACE instructions in the program are ignored, and the language processor pauses after nearly all instructions that are traced at the console (see the following for the exceptions). When the language processor pauses, indicated by a VM Read; or unlocking of the keyboard, three debug actions are available :
If an instruction has a syntax error in it, a standard message is displayed and you are prompted for input again. Similarly all the other SIGNAL conditions are disabled while the string is processed to prevent unintentional transfer of control.
During execution of the string, no tracing takes place, except that not zero return codes from host commands are displayed. Host commands are always executed (that is, are not affected by the prefix ! on TRACE instructions), but the variable RC is not set.
Once the string has been processed, the language processor pauses again for more debug input unless a TRACE instruction was entered. In this latter case, the language processor immediately alters the tracing action (if necessary) and then continues executing until the next pause point (if any). To alter the tracing action (from All to Results, for example) and then re-execute the instruction, you must use the built-in function TRACE(). For example, CALL TRACE I changes the trace action to "I" and allows re-execution of the statement after which the pause was made. Interactive debug is turned off, when it is in effect, if a TRACE instruction uses a prefix, or at any time when a TRACE Off or TRACE with no options is entered.
Exceptions: Some clauses cannot safely be re-executed, and therefore, the language processor does not pause after them, even if they are traced.
These are:
In this example, we trace the procedure interactively (?i). We use the possibility to interact with the procedure at each statement:
» ttest ?i 8 *-* do i=1 to 4 >L> "1" >L> "4" +++ Interactive trace. TRACE OFF to end debug, ENTER to continue. +++ » say i 1 » 9 *-* i=i+1 >V> "1" >L> "1" >O> "2" » = *-* i=i+1 >V> "2" >L> "1" >O> "3" » say i 3 » i=2 » 10 *-* end 8 *-* do i=1 to 4 9 *-* i=i+1 >V> "3" >L> "1" >O> "4" 10 *-* end 8 *-* do i=1 to 4 11 *-* call subrout 13 *-* SUBROUT: » trace off Value of i= 5 +++ Interactive trace. TRACE OFF to end debug, ENTER to continue. +++ » trace off Ready; T=0.01/0.03 11:51:12
We see that we can:
We can in fact issue any command that we could have coded in the procedure itself. It is as if the interpreter waits for the next statement to come from the console instead of the file. The commands you issue have thus to conform the REXX coding rules (REXX is in control). Let's look at another example, where we issue a CMS command:
» ttest ?i 8 *-* do i=1 to 4 >L> "1" >L> "4" +++ Interactive trace. TRACE OFF to end debug, ENTER to continue. +++ » 'TYPE PROFILE EXEC A' /* PROFILE */ trace off 'ACCESS .TC.TCVM1.INSTRUCTORS C' 'CP LINK FSCIPOE 193 193 RR' 'ACCESS 193 E' exit » 9 *-* i=i+1 >V> "1" >L> "1" >O> "2" » 'RENAME PROFILE EXEC A1 = = A'i » do 2 +++ Interactive trace. Error 14: Incomplete DO/SELECT/IF. +++ » do 2;say 'Hello';end Hello Hello » 10 *-* end » trace off Ready; T=0.01/0.02 16:53:22
We first issued the CMS TYPE PROFILE EXEC command, which is executed immediately, resulting in the output at the terminal.
Later, we issue the RENAME command, but we use the variable i in the command. REXX interprets this statement before passing it to CMS, so the resulting command is RENAME PROFILE EXEC A1 = = A2 as i had the value 2 at that moment.
Then we issued the do 2 command and REXX refused. Indeed, we have to give valid and complete REXX instructions, so we corrected the error by issuing the do 2;say 'Hello';end statement.
Finally, we turned tracing off.
We didn't use arrays in our little test procedure, but the technique of issuing a DO-block is useful when you want to inspect the values of all (or part) of your elements in your array during interactive debug.
To visualize this, let's give a simple example. The procedure has initialized an array a. with all numbers from 1 to 10 before interactive trace was started...
8 *-* factorial=1 >>> "1" +++ Interactive trace. TRACE OFF to end debug, ENTER to continue. +++ » 9 *-* do i=1 to 10 >>> "1" >>> "10" » 10 *-* factorial=factorial*a.i >>> "1" » 11 *-* say 'Factorial of' i 'is' format(factorial,5) >>> "Factorial of 1 is 1" Factorial of 1 is 1 12 *-* end 9 *-* do i=1 to 10 » 10 *-* factorial=factorial*a.i >>> "2" » 11 *-* say 'Factorial of' i 'is' format(factorial,5) >>> "Factorial of 2 is 2" Factorial of 2 is 2 12 *-* end 9 *-* do i=1 to 10 » 10 *-* factorial=factorial*a.i >>> "6" » 11 *-* say 'Factorial of' i 'is' format(factorial,5) >>> "Factorial of 3 is 6" Factorial of 3 is 6 » say 'counter ='i;do j=i to 10;say a.j;end counter =3 3 4 5 6 7 8 9 10 » exit Ready; T=0.02/0.06 12:25:11
In the middle of the loop we issue
say 'counter ='i;do j=i to 10;say a.j;end
We ask for the current value of the loop counter (when tracing large loops, you may have forgotten at which iteration you were), and want to display the coming elements in the array.
Remark also that a simple exit is correctly interpreted by REXX and immediately canceled our procedure.
To end this discussion, let's give another 'real-life' example where the possibility to enter CMS commands proved to be very useful. The RACF utility procedure that allows to copy the RACF database from 9335 (FBA) to 9345 (CKD) disks failed due to a bug. The procedure was started again, now using interactive trace (TS), as this is easier to debug than to XEDIT the file and to try to understand the logic. Also, by effectively running the procedure, you can see the real values the variables get during execution and see only those parts of the procedure that get executed.
This is what we got (this is not the real console listing):
... 745 *-* "OSRUN ICHUT400 PARM='"stparms"'" >>> "OSRUN ICHUT400 PARM='INDD1 OUTDD1'" DMSOPN036E OPEN ERROR 4 ON INDD1 » 'Q FILEDEF' ... shows INDD1 is still defined ... ... as we know RACF's habits a bit, we checked accessed disks ... » 'Q DISK' ... olala, the input disk (INDD1), at address 200 isn't accessed anymore... » 'ACCESS 200 R' » = 745 *-* "OSRUN ICHUT400 PARM='"stparms"'" >>> "OSRUN ICHUT400 PARM='INDD1 OUTDD1'" ICHMSGxxx COPY of 200 to 400 completed successfuly » trace off Ready;
Thanks to the interactive tracing, we were able to correct the environment for the procedure (ACCESS command), and to re-execute the failing instruction.
Of course, you have to modify the source if you want to avoid the same error again in later runs. Commands issued during interactive trace don't change the EXEC file on the disk !
This concludes the chapter on Interactive Tracing. Chapter 7 will study how tracing can be controlled.