To begin a debugging session on a specific routine, type the following command at the GTM prompt:
GTM>DO ^routinename
You can also begin a debugging session by pressing <CTRL-C> after running an M application at the shell. To invoke Direct Mode by pressing <CTRL-C>, process must have the Principal Device in the CENABLE state and not have the device set to CTRAP=$C(3).
When GT.M receives a <CTRL-C> command from the principal device, it invokes Direct Mode at the next opportunity, (usually at a point corresponding to the beginning of the next source line). GT.M can also interrupt at a FOR loop iteration or during a command of indeterminate duration such as LOCK, OPEN or READ. The GT.M USE command enables/disables the <CTRL-C> interrupt with the [NO]CENABLE deviceparameter. By default, GT.M starts <CTRL-C> enabled. The default setting for <CTRL-C> is controlled by $gtm_nocenable which controls whether <CTRL-C> is enabled at process startup. If $gtm_nocenable has a value of 1, "TRUE" or "YES" (case-insensitive), and the process principal device is a terminal, $PRINCIPAL is initialized to a NOCENABLE state where the process does not recognize <CTRL-C> as a signal to enter direct mode. No value, or other values of $gtm_nocenable initialize $PRINCIPAL with the CENABLE state. The [NO]CENABLE deviceparameter on a USE command can still control this characteristic from within the process.
GT.M displays the GTM> prompt on the principal device. Direct Mode accepts commands from, and reports errors to, the principal device. GT.M uses the current device for all other I/O. If the current device does not match the principal device when GT.M enters Direct Mode, GT.M issues a warning message on the principal device. A USE command changes the current device. For more information on the USE command, see ChapterA 9: a??Input/Output Processinga??.
The default "compile-as-written" mode of the GT.M compiler lets you run a program with errors as part of the debugging cycle. The object code produced includes all lines that are correct and all commands on a line with an error, up to the error. When GT.M encounters an error, it XECUTEs non empty values of $ETRAP or $ZTRAP. By default $ZTRAP contains a BREAK command, so GT.M enters Direct Mode.
The rest of the chapter illustrates the debugging capabilities of GT.M by taking a sample routine, dmex, through the debugging process. dmex is intended to read and edit a name, print the last and first name, and terminate if the name is an upper-case or lower-case "Q".
Each of the remaining sections of the chapter uses dmex to illustrate an aspect of the debugging process in GT.M.
To create or edit a routine, use the ZEDIT command. ZEDIT invokes the editor specified by the EDITOR environment variable, and opens the specified file. dmex.m, for editing.
Example:
GTM>ZEDIT "dmex"
Once in the editor, use the standard editing commands to enter and edit text. When you finish editing, save the changes, which returns you to Direct Mode.
To display M source code for dmex, use the ZPRINT command.
Example:
GTM>ZPRINT ^dmex
dmex;dmex - Direct Mode example
;
beg
for read !,"Name: ",name do name
quit
name
set ln=$l(name)
if ln,$extract("QUIT",1,ln)=$tr(name,"quit","QUIT") do
. s name="Q"
. quit
if ln<30,bame?1.a.1"-".a1","1" "1a.ap do print quit
write !,"Please use last-name, "
write "first-name middle-initial or 'Q' to Quit."
quit
print
write !,$piece(name,", ",2)," ",$piece(name,", ")
quit
GTM>
This uses the ZPRINT command to display the routine dmex.
![[Note]](../common/images/note.jpg) | Note |
---|
The example misspells the variable name as bame. |
To execute an M routine interactively, it is not necessary to explicitly compile and link your program. When you refer to an M routine that is not part of the current image, GT.M automatically attempts to compile and ZLINK the program.
Example:
GTM>DO ^dmex
Name: Revere, Paul
%GTM-E-UNDEF, Undefined local variable: bame
At M source location name+3^dmex
GTM>
In this example GT.M places you in Direct Mode, but also cites an error found in the program with a run-time error message. In this example, it was a reference to bame, which is undefined.
To see additional information about the error message, examine the $ECODE or $ZSTATUS special variables.
$ECODE is read-write intrinsic special variable that maintains a list of comma delimited codes that describe a history of past errors - the most recent ones appear at the end of the list. In $ECODE, standard errors are prefixed with an "M", user defined errors with a "U", and GT.M errors with a "Z". A GT.M code always follows a standard code.
$ZSTATUS is a read-write intrinsic special variable that maintains a string containing the error condition code and location of the last exception condition occurring during routine execution. GT.M updates $ZSTATUS only for errors found in routines and not for errors entered at the Direct Mode prompt.
Example:
GTM>WRITE $ECODE
,M6,Z150373850
This example uses a WRITE command to display $ECODE.
Example:
GTM>WRITE $ZS
150373850,name+3^dmex,%GTM-E-UNDEF, Undefined
local variable: bame
This example uses a WRITE command to display $ZSTATUS. Note that the $ZSTATUS code is the same as the "Z" code in $ECODE.
You can record the error message number, and use the $ZMESSAGE function later to re-display the error message text.
Example:
GTM>WRITE $ZM(150373850)
%GTM-E-UNDEF, Undefined local variable: !AD
This example uses a WRITE command and the $ZMESSAGE function to display the error message generated in the previous example. $ZMESSAGE() is useful when you have a routine that produces several error messages that you may want to examine later. The error message reprinted using $ZMESSAGE() is generic; therefore, the code !AD appears instead of the specific undefined local variable displayed with the original message.
When GT.M encounters a run-time or syntax error, it stops executing and displays an error message. GT.M reports the error in the message. In this case, GT.M reports an undefined local variable and the line in error, name+3^dmex. Note that GT.M re-displays the GTM> prompt so that debugging may continue.
To re-display the line and identify the error, use the ZPRINT command.
Example:
GTM>ZPRINT, name+3
%GTM-E-SPOREOL, Either a space or an end-of-line was expected but not found
ZP, name+3
^_____
GTM>
This example shows the result of incorrectly entering a ZPRINT command in Direct Mode. GT.M reports the location of the syntax error in the command line with an arrow. $ECODE and $ZSTATUS do not maintain this error message because GT.M did not produce the message during routine execution. Enter the correct syntax, (i.e., remove the comma) to re-display the routine line in error.
Example:
GTM>WRITE $ZPOS
name+3^dmex
This example writes the current line position.
$ZPOSITION is a read-only GT.M special variable that provides another tool for locating and displaying the current line. It contains the current entry reference as a character string in the format label+offset^routine, where the label is the closest preceding label. The current entry reference appears at the top of the M invocation stack, which can also be displayed with a ZSHOW "S" command.
To display the current value of every local variable defined, use the ZWRITE command with no arguments.
Example:
GTM>ZWRITE
ln=12
name="Revere, Paul"
This ZWRITE displays a listing of all the local variables currently defined.
![[Note]](../common/images/note.jpg) | Note |
---|
ZWRITE displays the variable name. ZWRITE does not display a value for bame, confirming that it is not defined. |
The ZSTEP command provides a powerful tool to direct GT.M execution. When you issue a ZSTEP from Direct Mode, GT.M executes the program to the beginning of the next target line and performs the ZSTEP action.
The optional keyword portion of the argument specifies the class of lines where ZSTEP pauses its execution, and XECUTEs the ZSTEP action specified by the optional action portion of the ZSTEP argument. If the action is specified, it must be an expression that evaluates to valid GT.M code. If no action is specified, ZSTEP XECUTEs the code specified by the $ZSTEP intrinsic special variable; by default $ZSTEP has the value "B", which causes GT.M to enter Direct Mode.
ZSTEP actions, that include commands followed by a BREAK, perform the specified action, then enter Direct Mode. ZSTEP actions that do not include a BREAK perform the command action and continue execution. Use ZSTEP actions that issue conditional BREAKs and subsequent ZSTEPs to perform tasks such as test for changes in the value of a variable.
Use ZSTEP to incrementally execute a routine or a series of routines. Execute any GT.M command from Direct Mode at any ZSTEP pause. To resume normal execution, use ZCONTINUE. Note that ZSTEP arguments are keywords rather than expressions, and they do not allow indirection.
Example:
GTM>ZSTEP INTO
Break instruction encountered during ZSTEP action
At M source location print^dmex
GTM>ZSTEP OUTOF
Paul Revere
Name: Q
%GTM-I-BREAKZST, Break instruction encountered during ZSTEP action
At M source location name^dmex
GTM>ZSTEP OVER
Break instruction encountered during ZSTEP action
At M source location name+1^dmex
This example shows using the ZSTEP command to step through the routine dmex, starting where execution was interrupted by the undefined variable error. The ZSTEP INTO command executes line name+3 and interrupts execution at the beginning of line print.
The ZSTEP OUTOF continues execution until line name. The ZSTEP OVER, which is the default, executes until it encounters the next line at this level on the M invocation stack. In this case, the next line is name+1. The ZSTEP OVER could be replaced with a ZSTEP with no argument because they do the same thing.
M DOs, XECUTEs, and extrinsics add a level to the invocation stack. Matching QUITs take a level off the stack. When GT.M executes either of these commands, an extrinsic function, or an extrinsic special variable, it "pushes" information about the new environment on the stack. When GT.M executes the QUIT, it "pops" the information about the discarded environment off the stack. It then reinstates the invoking routine information using the entries that have now arrived at the active end of the stack.
![[Note]](../common/images/note.jpg) | Note |
---|
In the M stack model, a FOR command does not add a stack frame, and a QUIT that terminates a FOR loop does not remove a stack frame. |
The $STACK intrinsic special variable and the $STACK() function provide a mechanism to access M stack context information.
Example:
GTM>WRITE $STACK
2
GTM>WRITE $STACK(2,"ecode")
,M6,Z150373850,
GTM>WRITE $STACK(2,"place")
name+3^dmex
GTM>WRITE $STACK(2,"mcode")
if ln<30,bame?1.a.1"-".a1","1" "1a.ap do print q
GTM>
This example gets the value of $STACK and then uses that value to get various types of information about that stack level using the $STACK() function. The "ecode" value of the error information for level two, "place" is similar to $ZPOSITION, "mcode" is the code for the level.
In addition to the $STACK intrinsic special variable, which provides the current stack level, $STACK(-1) gives the highest level for which $STACK() can return valid information. Until there is an error $STACK and $STACK(-1) are the same, but once $ECODE shows that there is an "current" error, the information returned by $STACK() is frozen to capture the state at the time of the error; it unfreezes after a SET $ECODE="".
Example:
GTM>WRITE $STACK
2
GTM>WRITE $STACK(-1)
2
GTM>
This example shows that under the conditions created (in the above example), $STACK and $STACK(-1) have the same value.
The $STACK() can return information about lower levels.
Example:
+1^GTM$DMOD
GTM>WRITE $STACK(1,"ecode")
GTM>WRITE $STACK(1,"place")
beg^dmex
GTM>WRITE $STACK(1,"mcode")
beg for read !,"Name:",namde do name
GTM>
This example shows that there was no error at $STACK level one, as well as the "place" and "mcode" information for that level.
The ZSHOW command displays information about the M environment.
Example:
GTM>zshow "*"
$DEVICE=""
$ECODE=",M6,Z150373850,"
$ESTACK=2
$ETRAP=""
$HOROLOG="64813,21971"
$IO="/dev/pts/0"
$JOB=14550
$KEY=$C(13)
$PRINCIPAL="/dev/pts/0"
$QUIT=0
$REFERENCE=""
$STACK=2
$STORAGE=2147483647
$SYSTEM="47,gtm_sysid"
$TEST=1
$TLEVEL=0
$TRESTART=0
$X=0
$Y=26
$ZA=0
$ZALLOCSTOR=680360
$ZAUDIT=0
$ZB=$C(13)
$ZCHSET="M"
$ZCLOSE=0
$ZCMDLINE=""
$ZCOMPILE=""
$ZCSTATUS=0
$ZDATEFORM=0
$ZDIRECTORY="/path/to/the/current/directory"
$ZEDITOR=0
$ZEOF=0
$ZERROR="Unprocessed $ZERROR, see $ZSTATUS"
$ZGBLDIR="/path/to/the/global/directory"
$ZHOROLOG="64813,21971,720675,14400"
$ZICUVER=""
$ZININTERRUPT=0
$ZINTERRUPT="IF $ZJOBEXAM()"
$ZIO="/dev/pts/0"
$ZJOB=0
$ZKEY=""
$ZLEVEL=3
$ZMAXTPTIME=0
$ZMODE="INTERACTIVE"
$ZONLNRLBK=0
$ZPATNUMERIC="M"
$ZPIN="/dev/pts/0"
$ZPOSITION="name+5^dmex"
$ZPOUT="/dev/pts/0"
$ZPROMPT="GTM>"
$ZQUIT=0
$ZREALSTOR=697936
$ZRELDATE="20180614 00:33"
$ZROUTINES=". /usr/lib/fis-gtm/V6.3-005_x86_64 /usr/lib/fis-gtm/V6.3-005_x86_64/plugin/o(/usr/lib/fis-gtm/V6.3-005_x86_64/plugin/r)"
$ZSOURCE=""
$ZSTATUS="150373850,name+5^dmex,%GTM-E-UNDEF, Undefined local variable: bame"
$ZSTEP="B"
$ZSTRPLLIM=0
$ZSYSTEM=0
$ZTIMEOUT=-1
$ZTDATA=0
$ZTDELIM=""
$ZTEXIT=""
$ZTLEVEL=0
$ZTNAME=""
$ZTOLDVAL=""
$ZTRAP="B"
$ZTRIGGEROP=""
$ZTSLATE=""
$ZTUPDATE=""
$ZTVALUE=""
$ZTWORMHOLE=""
$ZUSEDSTOR=671689
$ZUT=1528970771720738
$ZVERSION="GT.M V6.3-005 Linux x86_64"
$ZYERROR=""
ln=8
name="John Doe"
/dev/pts/0 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=165 LENG=48
MLG:0,MLT:0
GLD:*,REG:*,SET:0,KIL:0,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:0
DWT:0,NTW:0,NTR:0,NBW:0,NBR:0,NR0:0,NR1:0,NR2:0,NR3:0,TTW:0,TTR:0,TRB:0,TBW:0,
TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0,ZTR:0,DFL:0,
DFS:0,JFL:0,JFS:0,JBB:0,JFB:0,JFW:0,JRL:0,JRP:0,JRE:0,JRI:0,JRO:0,JEX:0,DEX:0,
CAT:0,CFE:0,CFS:0,CFT:0,CQS:0,CQT:0,CYS:0,CYT:0,BTD:0,WFR:0,BUS:0,BTS:0,STG:0,
KTG:0,ZTG:0,DEXA:0,GLB:0,JNL:0,MLK:0,PRC:0,TRX:0,ZAD:0,JOPA:0,AFRA:0,BREA:0,
MLBA:0,TRGA:0,WRL:0,PRG:0,WFL:0,WHE:0,INC:0
name+5^dmex ($ZTRAP)
(Direct mode)
beg+1^dmex:51a6a6c4739b004094c4545246ce4d68
+1^GTM$DMOD (Direct mode)
GTM>
This example uses the asterisk (*) argument to show all information that ZSHOW offers in the context debugging the error in the ^dmex routine. First are the Intrinsic Special Variables ($DEVICE-$ZYERROR, also available with ZSHOW "I"), then the local variables (bame, ln and name, also available with ZSHOW "V"), then the ZBREAK locations (name+3^dmex, also available with ZSHOW "B"), then the device information (also available with ZSHOW "D"), then the M stack (also available with ZSHOW "S"). ZSHOW "S" is the default for ZSHOW with no arguments.
Context information that does not exist in this example includes M LOCKs of this process (ZSHOW "L").
In addition to directing its output to the current device, ZSHOW can place its output in a local or global variable array. For more information, see the command description a??ZSHowa??.
![[Note]](../common/images/note.jpg) | Note |
---|
ZSHOW "V" produces the same output as ZWRITE with no arguments, but ZSHOW "V" can be directed to a variable as well as a device. |
The ZGOTO command transfers control from one part of the routine to another, or from one routine to another, using the specified entry reference. The ZGOTO command takes an optional integer expression that indicates the M stack level reached by performing the ZGOTO, and an optional entry reference specifying the location to where ZGOTO transfers control. A ZGOTO command, with an entry reference, performs a function similar to the GOTO command with the additional capability of reducing the M stack level. In a single operation, the process executes $ZLEVEL-intexpr, implicit QUITs from DO or extrinsic operations, and a GOTO operation transferring control to the named entry reference.
The ZGOTO command leaves the invocation stack at the level of the value of the integer expression. GT.M implicitly terminates any intervening FOR loops and unstacks variables stacked with NEW commands, as appropriate.
ZGOTO $ZLEVEL:LABEL^ROUTINE takes the same action as GO LABEL^ROUTINE.
ZGOTO $ZLEVEL-1 produces the same result as QUIT (followed by ZCONTINUE, if in Direct Mode).
If the integer expression evaluates to a value greater than the current value of $ZLEVEL, or less than zero (0), GT.M issues a run-time error.
If ZGOTO has no entry reference, it performs some number of implicit QUITs and transfers control to the next command at the specified level. When no argument is specified, ZGOTO 1 is the result, and operation resumes at the lowest level M routine as displayed by ZSHOW "S". In the image invokedby mumps -direct, or a similar image, a ZGOTO without arguments returns the process to Direct Mode.
Now that the routine errors have been identified, correct them in the M source file. Use ZEDIT to invoke the editor and open the file for editing. Correct the errors previously identified and enter to exit the editor.
Example:
GTM>zedit "dmex.m"
dmex;dmex - Direct Mode example
;
beg
for read !,"Name: ",name do name quit:name="Q"
quit
name
set ln=$length(name)
if ln,$extract("QUIT",1,ln)=$tr(name,"quit","QUIT") do
. set name="Q"
. quit
if ln<30,name?1.a.1"-".a1","1" "1a.ap do print quit
write !,"Please use last-name, "
write "first-name middle-initial or 'Q' to Quit."
quit
print
write !,$piece(name,", ",2)," ",$piece(name,", ")
quit
This example shows the final state of a ZEDIT session of dmex.m. Note that the infinite FOR loop at line beg is corrected.