MAINDEBUG User's Guide, Chapter 4

previous   next   top   complete contents   complete index   framed top   this page unframed


4. Debugging Commands

4.1. Most Recently Used Field Bases: $p1 and $p2

The debugger maintains the POINTER variable $p1 as the value of the most recent non-Zero POINTER p used in “.F p.f”, “V p.f”, “.V p”, “H p.f”, or “.H p”.

It maintains $p2 as the previous different value of $p1.

Both $p1 and $p2 are classified according to the records or data sections that they reference, so they may be used in expressions such as $p1.f, where f is the name of a field in the record currently referenced by $p1.

The following commands show the field f of successively linked records of CLASS c:

v p.f          # sets $p1 to p
v $p1.link.f   # sets $p1 to p.link$p2 to p
v $p1.link.f   # sets $p1 to p.link.link$p2 to p.link
v $p1.link.f   # sets $p1 to p.link.link.link,
               #   
$p2 to p.link.link
...
v $p1.link.f   # sets $p1 to p.link.link....link,
               #   
$p2 to previous $p1

In each case $p2 is set to the previous value of $p1.

4.2. Displaying ARRAY Slices: A ary{,l1,u1{,l2,u2{,l3,u3}}}

The A command displays elements of the dynamic ARRAY ary. In a one-dimensional ARRAY, l2 and subsequent arguments are omitted, and the elements ary[i], i ranging from l1 to u1, are displayed. In a two-dimensional ARRAY, l3 and u3 are omitted, and the elements ary[i,j], i ranging from l1 to u1, j ranging from l2 to u2, are displayed. In a three-dimensional ARRAY, the elements ary[i,j,k], i ranging from l1 to u1, j ranging from l2 to u2, and k ranging from l3 to u3, are displayed. Later subscripts vary faster than earlier ones; e.g., k varies faster than j, and j faster than i.

The output shows the subscript(s) of each element and its value. For example, A ary,0,2 might display the following, assuming ary is a one-dimensional INTEGER ARRAY:

ary,0,2 =
[0] = 6
[1] = 113
[2] = -9

An asterisk (*) may be used for any li or ui to stand for the corresponding bound declared for the ARRAY. Trailing asterisks may be omitted, so that when no bounds are specified, all elements of the ARRAY are displayed.

Example 4–1. Uses of the A Command
A with no explicit arguments displays all elements of the ARRAY named by the current word.

A ,1,5 displays elements 1 through 5 of the ARRAY named by the current word.

ary may be a (LONG) INTEGER or (LONG) BITS constant that the user has determined to be the ADDRESS of an ARRAY; e.g., A 'H123456,1,10 is valid if 'H123456 is the ADDRESS of an ARRAY. ARRAYs may be moved during memory management, so that constant ADDRESSes may become invalid.

ary currently must be a dynamic ARRAY, not an inplace ARRAY.

4.2.1. ARRAY Display Example

Suppose an ARRAY ary is declared and initialized as follows:

INTEGER ARRAY(1 TO 3,1 TO 3) ary;
new(ary); INIT ary (1,2,3,4,5,6,7,8,9);

Some debugger A commands that might be used on ary and their results are:

Debugger Command Display Same as
A ary,1,1,1,1 [1,1] = 1 V ary[1,1]
A ary,1,1,*,* [1,1] = 1
[1,2] = 2
[1,3] = 3
A ary,1,1
A ary,1,*,1,1 [1,1] = 1
[2,1] = 4
[3,1] = 7
 
A ary,1,1,2,3 [1,2] = 2
[1,3] = 3
A ary,1,1,2
A ary,1,2,*,* [1,1] = 1
[1,2] = 2
[1,3] = 3
[2,1] = 4
[2,2] = 5
[2,3] = 6
A ary,1,2
A ary,1,3,1,3 [1,1] = 1
[1,2] = 2
[1,3] = 3
[2,1] = 4
[2,2] = 5
[2,3] = 6
[3,1] = 7
[3,2] = 8
[3,3] = 9
A ary

4.3. Setting Breakpoints: {+}B{[condition]}{:commands}

This form of the B command sets a breakpoint in the current MODULE. Control is given to the debugger when the breakpoint is encountered during execution; the command and breakpoint contexts are then set to the context in which the breakpoint was reached.

The breakpoint is set at the iUnit (see Section 2.5) that corresponds to the current cursor position. The cursor must be positioned somewhere within the statement on which the breakpoint is to be set. The cursor is considered to be positioned within a statement if it is on the first character of the statement or any character up to the start of the next statement or the end of the PROCEDURE. The cursor can also be positioned at the start of a PROCEDURE, meaning to break on the first statement in the PROCEDURE.

[condition] and :commands are optional.

condition is an expression that is evaluated whenever execution reaches the breakpoint. If it is FALSE no break occurs. condition is any MAINSAIL expression valid in the break context, i.e., any expression that could legally appear in the source immediately before the statement on which the breakpoint is placed. condition is not compiled until the first time the breakpoint occurs, so an invalid condition is not recognized until then. If an invalid condition is recognized, a break occurs, an error message is issued, and any commands associated with the breakpoint are not executed.

If + is specified, the breakpoint is an ignore-count breakpoint; i.e., it is taken even if the count specified to the C command has not yet been reached.

Each time the breakpoint occurs, commands is executed as if it were typed in response to the debugger's prompt. If commands contains the C (Continue) command, the debugger automatically continues from the break (commands after C are ignored).

Example 4–2. Uses of the B Command
B[i = 5] breaks when control reaches the breakpoint and the variable i is equal to 5.

B:Vs;C breaks, shows the value of s, then continues.

commands must be enclosed in brackets if another command is to follow the B command on the same command line. Otherwise, the debugger has no way of knowing where commands ends and the next command begins. If commands is present but not enclosed in brackets, then the rest of the command line starting after the : is used as commands.

When a breakpoint is set, the debugger issues a message to this effect, indicating the MODULE and iUnit at the break.

4.3.1. Where Breakpoints May Be Set

In the figures in this section, the caret (^) appears immediately below the beginnings of constructs on which MAINDEBUG breakpoints may be set. The carets do not appear in MAINSAIL source text and are not displayed by MAINDEBUG.

Breakpoints may be placed on any MAINSAIL statement (except a BEGIN statement) or on an END. They may also be placed on the contraction EF (for ELSE IF), which implicitly contains the start of an IF statement:

IF foo THENB
^
    
WHILE i > j DO
    ^
        
IF bar(s,i,jTHEN RETURN
        ^                  ^
        
EF baz(s,iTHEN gak(i,j);
        ^                ^
    
getNextI(i,jEND;
    ^             ^

The rules for placing breakpoints on something other than a non-empty statement are as follows:

4.3.2. Setting a Breakpoint in a Specific MODULE Instance or Coroutine

Breakpoints are associated with a MODULE's control section, i.e., with the code that implements its PROCEDUREs. Since all instances (data sections) of a MODULE in all coroutines share the same control section, confusing interactions can occur if you mean for a breakpoint to be associated with just one instance of a MODULE or just one coroutine when the MODULE has several instances or is running in several coroutines.

A conditional breakpoint can be used in conjunction with a debugger variable (see Section 4.7) to cause the breakpoint to be taken in only one data section or coroutine. First declare a debugger POINTER variable, say p:

.D POINTER p;

Then (if the data section or coroutine desired is the current one) assign p the value of the desired data section or coroutine with:

XS p := thisDataSection

or:

XS p := $thisCoroutine

(if the target data section or coroutine is not the current one, you must find some other way of assigning its value to p). Then set the breakpoint with the appropriate condition, i.e.:

B[thisDataSection = p]

or:

B[$thisCoroutine = p]

4.4. Setting a Breakpoint at a Specified PROCEDURE: {+}B@

The full syntax for this command is:

{+}B@{module.}procedure{[condition]}{:command}

The breakpoint is put at the beginning of the PROCEDURE procedure in the MODULE module. If module. is not specified, the current MODULE is used. For example, to put a breakpoint at the PROCEDURE findNext in the current MODULE:

b@findnext

To put a breakpoint at the PROCEDURE hash in the MODULE SAMPLE:

b@sample.hash

The @ must immediately follow the B. module and procedure are direct arguments.

condition and command are as described in Section 4.3.

4.5. Setting a Breakpoint at a Specified iUnit: {+}B@

The full syntax for this command is:

{+}Bmodule1.iUnit1[condition1]:command1, ..., modulen.iUnitn[conditionn]:commandn

Breakpoints are set in the specified MODULEs. Control is given to the debugger when any of the breakpoints is encountered during execution.

The @ must immediately follow the B. modulei, iUniti, conditioni, and commandi are direct arguments.

A breakpoint is set at iUniti of the MODULE modulei for each modulei.iUniti specified. iUniti must correspond to the start of a statement in modulei. If modulei. is omitted, the current MODULE is used (an error occurs if there is no current MODULE). [conditioni] and :commandi are optional, and have the same form and function as the [condition] and :commands fields described in Section 4.3. commandi must be enclosed in brackets if there is another argument for B@ or another command after the B@ on the same command line.

If + is specified, the breakpoint is an ignore-count breakpoint; i.e., it is taken even if the count specified to the C command has not yet been reached.

Use of this command when the iUnit of a desired breakpoint is known (e.g., from previous debugging activity) eliminates the need to bring in a file and then use MAINDEBUG's or MAINEDIT's editing commands to position to the statement at which the break is to be set.

4.6. Continuing: {n}{.{i}}C

The C command continues execution until the nth breakpoint is encountered, or until an ignore-count breakpoint is encountered.

For the purposes of the C command, a conditional breakpoint is considered to be “encountered” only if its associated condition is TRUE.

The :commands part of any breakpoint skipped over by the C command is ignored; i.e., the commands are not executed.

Ignoring the optional count {n}, there are three valid forms of the C command:

4.7. Declaring Debugger Variables: .D d1;...;dn {END}

The di arguments to the .D command are MAINSAIL variable declarations. The declarations are compiled in the current command context, and the declared debugger variables can then be used in later debugger commands in any context. MAINSAIL macro definitions (i.e., using DEFINE or REDEFINE) may also occur among the di.

The terminating END is required if additional debugger commands are to be given on the same line as the .D command; the END is a terminating token for the compiler. Alternatively, the di may be enclosed in brackets: .D[d1;...;dn].

.D with no arguments uses @1 as the default argument; i.e., the current line supplies the argument text and is expected to consist of valid MAINSAIL definitions and declarations. In the display interface, the editor can be used to prepare n lines of definitions and declarations in a separate buffer, and then the .D@n command can be issued with the cursor anywhere on the first line.

To avoid confusion, the declared identifiers should not be the same as an identifier in the program being debugged.

Example 4–3. Uses of the .D Command
.D INTEGER ddi1STRING dds1POINTER(cddp1;

declares three debugger variables.

.D DEFINE dm1 = "abc"; STRING dds1;

defines the debugger macro dm1, and declares the variable dds1.

.D@5

reads five lines starting at the current line. These lines are assumed to consist of definitions and declarations.

.D@ffoo.msl

reads the definitions and declarations from the file foo.msl. Thus, a file of generally useful definitions and declarations may be prepared and processed during any debug session.

A debugger variable may be used as an iterative variable in the FOR-clause of an iterative statement executed from the debugger (the language normally requires that iterative variables be local variables).

Newly created debugger variables are initialized to Zero.

4.8. Going to the Declaration of an Identifier: !D identifier

The !D command takes a single argument. The argument may be a simple identifier declared or defined in the current scope of the compiler context (see Section 2.4), or it can be of one of the following forms:

className.field
moduleName.field
pointerExpression.field

In each of these cases, the identifier to be found is the field.

The command moves the cursor to the declaration of the identifier and sets the compiler context there. For example:

}INITIAL PROCEDURE;
SAMPLE!d hash<eol>
In file /p/sample.msl

INTEGER PROCEDURE }hash (STRING s);
SAMPLE:

4.9. Executing MODULEs: {-}E {moduleOrFileName{ arguments}}

The E command is used to execute a specified MODULE, or to invoke the MAINSAIL executive.

This command reads the remainder of the current line. It interprets the line as an optional MODULE or file name, followed by optional arguments. If a MODULE name is specified, the MODULE is executed with the specified arguments. If a file name is specified, the file is assumed to contain a MAINSAIL object MODULE, which is executed with the specified arguments. Control returns to the debugger when the MODULE execution is complete.

If moduleOrFileName is omitted, the MAINSAIL executive is invoked (see Chapter 21 of the MAINSAIL Utilities User's Guide for a description of the MAINSAIL executive). The MAINSAIL executive prints an identifying banner, then prompts with * and waits for input. Control returns to the debugger when just <eol> is typed to the * prompt.

If no breakpoint is reached in the executed MODULE and control returns to the debugger, then the command and breakpoint contexts remain unchanged. If a breakpoint is reached, the contexts are changed to the context of the break, as usual.

Use this command to execute utility MODULEs, or to start execution of the program to be debugged by specifying the initial MODULE of that program.

Example 4–4. Use of the E Command
The commands:

b@xyz.1340
exyz

set a breakpoint at offset 1340 of XYZ, then execute XYZ.

The - modifier means do not put breakpoints in before running the MODULE. If specified, breakpoints are ignored (not reached) during the execution of the MODULE.

4.10. Displaying Individual Fields of Unclassified POINTERs: .F p,f1,f2,...

.F p,f1,f2,... is the same as V p.f1,p.f2,..., except that p can be an unclassified POINTER.

For V p.f the compiler must know p's CLASS c, and f must be a field of c; otherwise, the compiler issues an error message. However, for .F p,f, the debugger looks in the CLASS descriptor of the record pointed to by p and sees whether there is a field named f. If so, the CLASS descriptor indicates its type and displacement from the start of the record, so that the debugger has enough information to print its value. Since f is not compiled, it must be the actual name of a field rather than, say, a macro name that expands to a field name.

p may be a (LONG) INTEGER or (LONG) BITS constant that the user has determined to be the ADDRESS of a dynamic record or data section; e.g.:

.F 'H123456,f

is valid if 'H123456 is the ADDRESS of a dynamic record or data section with a data field f. Dynamic records and data sections may be moved during memory management, so that constant ADDRESSes may become invalid.

The .F command is particularly useful if the ADDRESS of a record is known, say 'H123456, and one or more of its fields are to be displayed: .F'H123456,field1,field2,.... The command V 'H123456.f1 would not compile, since 'H123456.f1 is not a valid MAINSAIL expression.

4.11. Displaying Hexadecimal Values: H {expression1, ..., expressionn}

The H command is identical to the V command, except that (LONG) INTEGER, (LONG) BITS, (LONG) REAL, ADDRESS, CHARADR, and POINTER values are displayed in hexadecimal, even if the preferred radix for the processor is not hexadecimal.

4.12. Displaying Hexadecimal Field Values: .H {p1, ..., pn}

The .H command is identical to the .V command, except that (LONG) INTEGER, (LONG) BITS, (LONG) REAL, ADDRESS, CHARADR, and POINTER values are displayed in hexadecimal, even if the preferred radix for the processor is not hexadecimal.

4.13. Information: I

The I command displays debugger information.

It displays information about both the command and breakpoint contexts, except that if one of the contexts is empty or incomplete, the missing information is not displayed.

The iUnit of the cursor position is also displayed. This information is useful if you need to issue a command based on iUnits.

The debuggable PROCEDURE count (the number of debuggable PROCEDUREs that have been entered during the current MAINSAIL session) is also displayed, as is the count break value, if set (see the description of the K command). MODULE, iUnit, condition, and command are shown for each breakpoint. T is shown for temporary breakpoints and I for ignore-count breakpoints.

Any debugger macro definitions are displayed.

Debugger options in effect (see Section 4.32) are displayed.

4.14. Brief Information: 1I

The 1I command is a short form of the I command which displays the following information about the command context:

The iUnit of the cursor position is also displayed.

In the display-oriented interface, all this information is shown on the message line.

4.15. Displaying the Synthesized Declaration of an Identifier: {+}.I identifier

The .I command takes a single argument of the same form and with the same semantics as the !D command argument.

Like the !D command, it displays the declaration of the identifier. However, unlike the !D command, it does not position the cursor at the declaration for the identifier; instead, it recreates the identifier's declaration text from the symbol table information. This command may be more informative than !D, e.g., if the declaration contains macros and it is hard to understand how the macros were expanded, or if you think the source text may have gotten out of sync with the intmod, or if the source text is not available.

The +.I command behaves like .I, except that if the identifier is a PROCEDURE, and the MODULE containing the PROCEDURE was compiled with the SAVEON subcommand, then the decompiled PROCEDURE body is displayed as well, if it is available.

Example:

SAMPLE+.i hash<eol>

hash was declared in module sample,
    
file /p/sample.msl at position 2368

INTEGER PROCEDURE hash (STRING s);
BEGIN
INTEGER h;
INTEGER i;
INTEGER j;
h := length(s);
i := h MIN 4;
j := 1;
WHILE (i .- 1) GEQ 0 DOB
    
j .+ 2;
    
h .+ (csread(s) * jEND;
RETURN(h MOD bucketsizeEND;

4.16. Jumping into PROCEDUREs: {n}J

The J command executes the next n statements, “jumping” into any debuggable PROCEDUREs invoked, then breaks. The J command is just like the S command, except that a break also occurs on the first statement of any debuggable PROCEDURE invoked, and at a call to $resumeCoroutine, J steps into the resumed coroutine.

Statements executed within nondebuggable PROCEDUREs are not counted among the n statements to be executed.

Commands on the same command line after a J command are ignored.

4.17. Count Breaks: K n

The K command sets the count break value to n.

Execution stops when the debuggable PROCEDURE count is incremented to n. Each time a PROCEDURE in a debuggable MODULE is entered, the count is incremented so that upon the nth entry to a debuggable PROCEDURE, the count break value is n.

PROCEDUREs compiled INLINE or nondebuggable do not increment the count.

The current count break value is displayed by the I command, or can be examined directly as the system variable $count (V $count).

Count breaks provide a means of isolating bugs. If the count value is noted when an error occurs (using the I command), program behavior can be observed by setting a count break for some value less than that at which the error occurred, letting the program run until the count break is reached, and then stepping (with the S and/or J commands) to the error. If a debug session is repeated except that some MODULEs are debuggable that previously were not, or vice versa, debug counts noted from the first session may not be applicable to the second.

K1 sets the count break value to 1, so that a break occurs the first time a debuggable PROCEDURE is entered. A convenient way to start a debugging session is to issue K1Emodule to the debugger, which sets the count break to 1, then executes the specified MODULE. If the MODULE is debuggable, execution breaks at the start of its INITIAL PROCEDURE.

4.17.1. K Command Arguments Starting with +

To reduce the chance of mistyping during long, repetitive count break searches, the debugger's K command takes a numerical argument starting with + to mean break at the current count plus the specified value. For example, if $count is 27916300, then K+100 means “break at count 27916400”.

Most window systems let you copy and then repeatedly paste a command line like K+100C, which provides a convenient way of stopping at series of count breaks 100 apart.

4.18. Removing a Count Break: -K

-K removes the current count break, if there is one.

4.19. Setting Context to Current Breakpoint: M

This form of the M command (no argument) sets the command context and the cursor to the current breakpoint context. This is a convenient way to get the cursor back to the current breakpoint after the cursor has been moved around during debugging commands. If the debugger was invoked by means of the DEBUG response to the Error response: prompt, the command context is set to the point of the error.

4.20. Setting Context to a MODULE: M s

M s sets the command context to the MODULE specified by s.

s is either a MODULE name or a file name. If a MODULE name is specified, the MODULE context is set to the bound instance for that MODULE, if it exists, and the file context is set to the start of the file that the compiler first encountered when the MODULE was compiled. If a file name is specified, then that file is assumed to contain either some object MODULE m or an intmod m, and the effect is the same as M m.

Only the MODULE and file parts of the command context are set.

See Section 4.21 for setting the context to a particular instance of a MODULE.

Enclose the argument to the M command in brackets if it contains a space, tab, semicolon, or brackets.

4.21. Setting Context to a Particular MODULE Instance: .M p

p must point to a data section for some MODULE m. The command context is set to that instance of m. The PROCEDURE and iUnit parts of the command context are not set.

p may be a POINTER or ADDRESS expression or a (LONG) INTEGER or (LONG) BITS constant. p should be a value that the user has determined to be the ADDRESS of a data section; e.g.:

.M 'H123456

is valid if 'H123456 is the ADDRESS of a data section. Data sections may be moved during memory management, so that constant ADDRESSes may become invalid.

4.22. Releasing a MODULE: -M m

-M m, where m is a MODULE name, disposes the MODULE m (if it is present) and closes the intmod for m (if it is open). If the current command context's MODULE is set to m, the command context is cleared. The command also causes all debugger variables (those declared with .D) to be forgotten, in case some of the variables refer to classes in an intmod released with -M. The argument m is an identifier argument.

This command must be carried out for each MODULE m that has taken part in a debug session, and then been recompiled without exiting the debugger, and is to take part in further debugging. If this command is not given for such a MODULE m, then further debugging will use the old control section for m if it is still in memory, and the old intmod for m if it is still open. In other words, the old version of m will be used even though it has been recompiled, which can be quite confusing.

If you have been debugging and recompiling without exiting the debugger, and you start having problems such as the debugger claiming that the cursor is not on a statement when you try to set a breakpoint, or a recompiled MODULE seems to behave as if it had not been recompiled, then you have probably forgotten to do -M m on one or more MODULEs. An alternate way to ensure that there are no old objmods or intmods in memory is to exit the MAINSAIL session and start a new one.

If at any time during a MAINSAIL session you recompile a MODULE m that is in memory, and then continue the session in such a way that m will be used again, you must first dispose of m in order to use the newly compiled control section. As described above, you can use the -M command to do this if you are in the debugger. If you are not in the debugger, invoke the utility MODULE DISPSE, which prompts for MODULEs to be disposed. DISPSE does nothing about intmods, but they do not affect execution unless you are debugging, and if you reinvoke the debugger it will start out with no open intmods. If you recompile many MODULEs, then rather than try to dispose all of them using DISPSE, it is probably simplest to exit MAINSAIL and start a new MAINSAIL session.

If you are using the display debugger, the -M command does not discard any editor buffers corresponding to the disposed MODULE. You must do this explicitly (using editor commands) if the contents of the buffer get out of sync with the source file.

For example, if you are using another editor (like vi or EMACS) to make modifications to the source files for the program you are debugging during a MAINDEBUG session, you must kill any buffers (e.g., with the MAINED command Q.KbufferName) that correspond to the modified files once you make the modifications. Of course, if you are modifying the files by using MAINEDIT itself in the same MAINSAIL session in which you are debugging, you need not get rid of the editor buffers; however, once you have made your changes, you must save and recompile the files and issue the -M command in order to get the objmods and intmods in sync with the editor buffers.

4.23. Walking the Call Stack: {n}{-}N

N sets the command context to the nth debuggable caller or callee.

If - is not present, the context is set to the nth debuggable caller (calling PROCEDURE invocation) in relation to the current PROCEDURE (the PROCEDURE part of the current command context). If - is present, the context is set to the nth debuggable callee (called PROCEDURE invocation) in relation to the current PROCEDURE.

The N command allows the user to walk up and down the PROCEDURE call stack.

N commands are not remembered across program continuation, meaning that if you issue a C command, execution continues from the breakpoint context (including whatever exception may be active in that context) rather than from the command context.

4.24. Walking the Exception Stack: {n}{-}.N

If an exception is active in the current command context, .N sets the command context to the debuggable statement at which it was raised (i.e., in the raiser coroutine if it differs from the raisee coroutine). If the command context is empty, the debugger sets the context to the debuggable statement in which the current exception was raised, if any. The exception is not considered active in the new context.

-.N undoes the most recent .N command; i.e., the command context is put back to where it was before the most recent .N command, and the exception is considered active in the new context.

.N commands are not remembered across program continuation, meaning that if you issue a C command, execution continues from the breakpoint context (including whatever exception may be active in that context) rather than from the command context.

n.N performs the .N command n times, and n-.N performs the -.N command n times.

.N complains if there is no active exception; -.N complains if there is no -.N command to undo.

4.25. Setting Context to Current Breakpoint: +N

+N sets the command context to the current breakpoint context; it has the same effect as the M command with no arguments.

4.26. Setting Cursor to Current Command Context: !N

The !N command sets the cursor to the current command context. This is useful if you move the cursor away from the current context and want to move it back. Unlike +N, !N positions to the current command context, not the breakpoint context; it does not change the command context.

4.27. Setting the Current iUnit: O n

O (“Offset”) sets the position part of the command context.

The cursor is positioned to the file position corresponding to iUnit n in the current MODULE.

This command is useful for positioning to the offset given for a debuggable MODULE when an error occurs. The offset given in an error message for a nondebuggable MODULE differs from that given for the same MODULE compiled with the debug option, since additional code is generated for debuggable MODULEs. This means that nondebuggable MODULEs must be recompiled debuggable and the program rerun before the O command can be used with the offset given in an error message.

4.28. Opening a Coroutine: OC s

OC s changes the coroutine part of the command context to the coroutine with the name s. The PROCEDURE in the new context is the first debuggable PROCEDURE in the call chain starting at the resume point of coroutine s (an error message is given if there is no such PROCEDURE). The cursor indicates the point at which control last resided in that PROCEDURE in coroutine s. This PROCEDURE is the new current debugger context, so that, for example, its local variables can be examined, and the N and -N commands walk the new coroutine's stack.

The following STRINGs may be used in place of s to give a way to move around the coroutine tree, or follow the dynamic resume list, by following the indicated link of the coroutine for the current command context. For example, OC #UP moves the context to the current coroutine's parent:

#UP     #DOWN   #LEFT   #RIGHT  #PREV   #NEXT

Enclose s in brackets if it contains a space, tab, semicolon, or brackets.

4.29. Opening a PROCEDURE Frame: OF a

The OF command sets the context to the PROCEDURE with its stack frame at the ADDRESS a. You can find out the stack frame ADDRESS for a particular PROCEDURE invocation by running the utility MODULE CALLS; the stack frame ADDRESS for each PROCEDURE is displayed in the column labeled FRAMEHDR ADR.

4.30. Opening an Intmod Library: OI s

The OI command opens the intmod library with name s, and puts it at the head of the list of intmod libraries searched by the debugger. The debugger can now find intmods in s. Intmod searches are also governed by the MAINEX subcommands OPENINTLIB, INTFILE, INTLIB, and INTDEFAULT.

Enclose s in brackets if it contains a space, tab, semicolon, or brackets.

4.31. Opening an Objmod Library: OL s

The OL command opens the MODULE library with name s, making its objmods available for execution. Objmod searches are also governed by the MAINEX subcommands OPENEXELIB, EXEFILE, EXELIB, and EXEDEFAULT.

This command must be issued before the Em command if the MODULE m resides in the library s and s is not already open.

Enclose s in brackets if it contains a space, tab, semicolon, or brackets.

4.32. Debugger Options: {-}OP s

The OP command sets or clears debugger options. If - is present, the options are cleared; otherwise, they are set.

s is a sequence of options. The options are direct arguments and may be separated by spaces and tabs.

The currently available standard options are:

Option Meaning
D continually display interface/outer variables of current data section
F continually display local variables of current PROCEDURE frame (invocation)
R allow recursive debugging of PROCEDUREs
V verbose prompt
S check break conditions for watch expressions at each statement instead of only on PROCEDURE entry

The D option indicates displayCurrentDataSec mode. If this option is set, the interface and outer variables of the current data section are continually displayed. The option is initially set only for the Motif debugger (see the Motif-Based MAINSAIL Tools Reference Guide).

The F option indicates displayCurrentFrame mode. If this option is set, the variables of the current PROCEDURE frame (invocation) are continually displayed. The option is initially set only for the Motif debugger.

The V option indicates verbosePrompt mode. If set, the default prompt:

moduleName.procedureName:

is used in the line-oriented interface; if turned off, the line-oriented prompt is:

MAINDEBUG:

4.32.1. recursiveDebug and nonRecursiveDebug Modes

The option R sets recursiveDebug mode; -OP R sets nonRecursiveDebug mode. In nonRecursiveDebug mode, breakpoints are temporarily removed from the code, and count breaks are disabled, while the debugger is in control.

In recursiveDebug mode, the debugger leaves breakpoints in the code at all times, and leaves the count break value as set with the K command. Thus a breakpoint can occur even while the debugger itself is carrying out a user command if any code executed by the debugger has been compiled debuggable; this is called a recursive invocation of the debugger.

For example, if you have set a breakpoint in some PROCEDURE foo, and then execute the debugger command V foo, the breakpoint occurs during the V command. This is often quite useful. However, if any of the MAINSAIL runtime MODULEs used by the debugger (such as the MAINSAIL compiler or text editor) are compiled debuggable, an unexpected count break could occur in one of those MODULEs, leading to confusing output and possibly causing MAINSAIL to crash. Thus recursive invocation is useful if no system MODULEs are compiled debuggable, but is otherwise dangerous.

In standard releases, the MAINSAIL runtime system is not provided to customers with any MODULE compiled debuggable, so that recursive debugger invocation does not occur due to system MODULEs. However, there are times (e.g., during customer testing of new releases) when debuggable MODULEs are delivered. If the debugger detects that a supporting system MODULE is compiled debuggable, it clears recursiveDebug mode (i.e., it sets nonRecursiveDebug mode) to avoid the potential confusion caused recursive debugger invocations.

In nonRecursiveDebug mode, breakpoints are temporarily removed from the code, and count breaks are disabled, while the debugger is in control. They are restored when the debugger relinquishes control because of commands such as C, S, J, and during invocation of a MODULE with the E command. However, this means that user breaks do not occur while in nonRecursiveDebug mode (e.g., V foo, where a breakpoint has been set in foo, does not break since the breakpoint has been temporarily removed). Although this is really just a minor inconvenience, it is mentioned to avoid confusion should you notice that recursive breaks are not occurring. The I command indicates whether the debugger is currently in recursiveDebug mode or nonRecursiveDebug mode. The debugger prints a message whenever it clears recursiveDebug mode due to detecting a debuggable runtime MODULE.

4.32.2. breakForWatchExprsAtStmts Mode

By default, breakForWatchExprsAtStmts is not in effect, meaning that the time at which the program evaluates watch break conditions is whenever control enters a debuggable PROCEDURE (see Section 4.48 for a description of watch break conditions). This default changes implicitly if any of the watched expressions with a break condition contains local variables for the current PROCEDURE; in this case, the debugger checks the conditions more frequently, after the execution of each statement.

You can change the mode to breakForWatchExprsAtStmts explicitly by giving the OP s command, and turn off breakForWatchExprsAtStmts with -OP s.

4.32.3. Setting Initial Values for Options in Your Parameter File

The parameter file contains settings of parameters that you specify in the file. In Version 16.30 of MAINSAIL, the parameter file is called v1630.prm (in general, the name of the file depends on the version of MAINSAIL; it consists of the letter v followed by the major and minor version numbers followed by .prm). This file may reside on your home directory, the directory on which you are editing, or in both places (see the description in Chapter 28 of the MAINSAIL Language Manual for all the details). It is also possible for application programs to specify MAINDEBUG parameters, as described in Chapter 7.

The following MAINDEBUG options can be set as parameters:

Parameter Name Argument to OP Command
breakForWatchExprsAtStmts S
displayCurrentDataSec D
displayCurrentProcFrame F
recursiveDebug R
verbose V

The option is turned on if its argument is the keyword TRUE and turned off if its argument is FALSE.

For example, to specify that verbosePrompt mode should be the default and displayCurrentProcFrame should not be set by default, the parameter file should contain:

$GROUP $MAINDEBUG

verbose TRUE
displayCurrentProcFrame FALSE

4.33. Removing a Breakpoint: R

The R command removes a breakpoint. The cursor must be positioned at the breakpoint.

4.34. Removing Breakpoints at a Specified PROCEDURE: R@ {module.}procedure

This form of the R command removes the breakpoint at the beginning of the PROCEDURE procedure in the MODULE module (or in the current MODULE if module. is omitted).

4.35. Removing Breakpoints at Specified iUnits: R@ module1.iUnit1, ..., modulen.iUnitn

This form of the R@ command removes the specified breakpoints.

The @ must immediately follow the R. If modulei. is omitted, the current MODULE is used.

4.36. Removing All Breakpoints: R@@

R@@ removes all breakpoints.

@@ must immediately follow R.

4.37. Remote Debugging: Tracking Bugs That Go Away When You Use the Debugger with +R {program}, +!R host {program}

It is possible for the debugger to run in one MAINSAIL process and the program being debugged to run in another.

As of Version 16.30 of MAINSAIL, remote debugging is available only on UNIX, not on Windows.

The remote debugging facility was designed primarily to allow XIDAK to debug the runtime system and the debugger itself. However, since the remote debugging facility disturbs the memory of the child process as little as possible, it may be useful for debugging programs where the bug manifests itself reproducibly as long as you are not using the debugger, but goes away whenever you try invoking the debugger to track it. Such bugs are sensitive to the exact layout of memory. Bugs of this type are often due to the use of dangling POINTERs or STRINGs, and before trying remote debugging, you should eliminate this possibility by using the rigging facilities; see Chapter 6.

If you try rigging POINTERs and STRINGs but that does not catch your bug, you are ready to try remote debugging.

4.37.1. Preparation for Remote Debugging

In order to use remote debugging, you must have the MAINSAIL STREAMS package installed (see MAINSAIL STREAMS User's Guide). Furthermore, remote debugging works only when the child's and parent's terminal output can be redirected to different places. By default, the debugger tries to start up the child process using an xterm terminal emulator window; however, if you are not running X, or if your xterm program is installed someplace other than /usr/bin/X11, you will need to configure the remote debugger before using it by setting some parameters in your parameter file (e.g., v1630.prm).

4.37.1.1. Changing the Default Terminal Emulator Program
The MAINSAIL process to be debugged must run under a terminal emulator program. You must choose a program that is capable of handling a child process's I/O to stdin and stdout, but which does not itself do any I/O to stdin and stdout (xterm behaves this way).

To change the terminal emulator program, set the following two parameters in the $MAINDEBUG group of your parameter file:

remoteCmdLinePrefixNoNode
remoteCmdLinePrefixWithNode

These should be set to the name of a program and arguments which, followed by a MAINSAIL bootstrap name, make up a command line that invokes the terminal emulator which in turn runs MAINSAIL in the terminal emulator. The first parameter (remoteCmdLinePrefixNoNode) is used when debugging a child process on the current host (+R); the second (remoteCmdLinePrefixWithNode) when debugging a child process run on some other host (+!R hostName).

The default value for remoteCmdLinePrefixNoNode is:

/usr/bin/X11/xterm -e

The -e switch precedes the name of a program to run in the window, so following it with a MAINSAIL bootstrap name has the desired effect.

The default value for remoteCmdLinePrefixWithNode is:

/usr/bin/X11/xterm -d *:0 -e

The stream to the terminal emulator is opened on the node specified in the +!R command. In addition, any asterisk (*) characters in the command line are replaced with the node name. Thus, the default is to run xterm and its child on the specified host, and also to display the terminal window on the specified host.

4.37.2. Remote Debugging Commands

The debugger command to start a remote debugging session is +R (or, in the less common case where you want to debug a child process on a host other than the current one, +!R host. In this case, the specified host must be of the same platform as the current host). The command may be followed by a bootstrap name and arguments; the default is the name of the bootstrap that started the current MAINSAIL session, with no arguments (the bootstrap name is found as the value of the logical file name “(executable boot)”).

You cannot debug remotely and locally at the same time, so you should give the remote debugging command at the very start of your debugging session.

The debugger starts up a terminal emulator running the specified bootstrap, then suspends the execution of the child process. The parent displays the message:

Use C to continue remote execution

You can now set breakpoints, etc., in the child. When you issue the C command in the parent, the child resumes and runs until it hits a breakpoint or MAINSAIL exits. When the child hits a breakpoint, you may generally issue any debugger command you could use while debugging locally, so that aside from the way it starts up, a remote debugging session closely resembles a local debugging session.

4.38. Stepping into PROCEDUREs: {n}S

The S command executes the next n statements, “stepping” over PROCEDUREs, then breaks. The S command does not break within any invoked PROCEDURE (use the J command for this). Statements executed within invoked PROCEDUREs are not counted among the n statements to be executed.

Beware of breaking or single stepping on statements that involve low-level manipulations of memory written with the assumption that memory management does not occur during execution of the statements, since execution of the debugger between such statements could lead to memory management. This precludes the use of single stepping on many “sensitive” areas of the MAINSAIL runtime system involved with storage allocation. For this reason, the user should avoid stepping through any PROCEDURE bodies distributed as part of the MAINSAIL system.

When single stepping, the debugger breaks on each place it reaches where a breakpoint could be set (see Section 4.3.1); furthermore, the debugger breaks on each expansion call generated by the use of REPEATABLE parameters. For example, since the statement:

write(logFile,"Count: ",count,eol)

is compiled as if it were:

write(logFile,"Count: ");
write(logFile,count);
write(logFile,eol)

the S command stops three times at write.

If, while executing nS, a breakpoint is encountered before the nth statement has been executed, the debugger nevertheless breaks; i.e., breakpoints have precedence over the step count n.

At a call to $resumeCoroutine, the S command does not step into the resumed coroutine, but instead breaks when control next returns to the statement after the $resumeCoroutine call. Usually this occurs when the coroutine is next resumed; however, the breakpoint for the S command is associated with the control section, not with a coroutine, so that it could next be encountered in some coroutine other than the one in which the S command was given. The J command does step into coroutines.

Commands on the same command line after an S command are ignored.

4.39. Show Contents of Current PROCEDURE Stack Frame (Show All Local Variables of Current PROCEDURE): .SF

This command shows the values of all the local variables of the current PROCEDURE frame (invocation). An example of the output is:

SAMPLE2.HASH
  
BUCKETSIZE 131
  
H          348376
  
I          350216
  
J          0
  
S          "dkfjdfkjdf"

4.40. Show Contents of All PROCEDURE Stack Frames (Show Local Variables of All PROCEDUREs): .SS{s}

This command shows the PROCEDURE stack for the coroutine named s. If s is not specified, it shows the stack for the current coroutine. The command displays a line of the form:

moduleName.procedureName

for each frame (invocation) on the PROCEDURE stack. If the frame is for a debuggable PROCEDURE, it also shows the values of the local variables. An example of the output is:

$DEBUG.$DEBUGEXEC
$DEBUG.$PROGBREAK
$KERMOD.$BRKPNT
SAMPLE2.HASH
  
BUCKETSIZE 131
  
H          348376
  
I          350216
  
J          0
  
S          "dkfjdfkjdf"
SAMPLE1.INITIALPROC
  
BUCKETSIZE 131
  
S          "dkfjdfkjdf"
$KERMOD.$NEWDATASEC
$MAINEX.$INVOKEMODULE
$DEBUG.$DEBUGEXEC
$DEBUG.INITIALPROC
$KERMOD.$NEWDATASEC
$MAINEX.$INVOKEMODULE
$MAINEX.EXECUTEMODULE
$MAINEX.$MAINSAILEXEC
$KERMOD.RUNMAINSAIL
$KERMOD.INITIALPROC

4.41. Setting Temporary Breakpoints: {+}T{[condition]}{:command}

This command is like the B command, except that T sets a temporary breakpoint. All temporary breakpoints are removed whenever a break occurs.

4.42. Setting a Temporary Breakpoint at a Specified PROCEDURE: {+}T@

The full syntax for this command is:

{+}T@{module.}procedure[condition]:command

The effect is the same as that of the B@ command, except that T@ sets temporary breakpoints. All temporary breakpoints are removed whenever a break occurs.

4.43. Setting a Temporary Breakpoint at a Specified iUnit: {+}T@

The full syntax for this command is:

Tmodule1.iUnit1[condition1]:command1, ..., modulen.iUnitn[conditionn]:commandn

The effect is the same as that of the B@ command, except that T@ sets temporary breakpoints. All temporary breakpoints are removed whenever a break occurs.

4.44. Tracing PROCEDURE Calls: !T {fileName}

The !T command opens a trace file and writes the PROCEDURE name and argument values for each subsequently entered debuggable PROCEDURE, until tracing is turned off. If fileName is specified, that file is used; otherwise, the file TTY is used as the trace file.

PROCEDURE names in the trace file are indented according to their position on the PROCEDURE stack. More deeply indented PROCEDURE names represent more deeply nested PROCEDURE calls.

The trace file can become quite large, so use this feature judiciously.

The command -!T turns tracing off and closes the trace file.

4.45. Displaying Values: V expression1, ..., expressionn

Display the values of the specified expressions. The expressioni must be MAINSAIL expressions valid in the current command context, i.e., expressions that could legally appear in the source text at the point of the current PROCEDURE context. The expressioni may contain anything normal source text could contain, e.g., local variables, outer and interface variables of the current MODULE, macro calls, PROCEDURE calls, etc.

In the display debugger, the output from the V command is written to the buffer CMDLOG.

If the current line is:

IF nextEst := (x / est + est) / 2. THEN ...
   
a b        cd   e     f      g       (cursor positions)

then the indicated cursor positions result in the following expressions being compiled for V@l (argument text starts at cursor and extends to end of current line):

Cursor At Compiled Expression
a nextEst := (x / est + est) / 2.
b xtEst := (x / est + est) / 2. (probably an error)
c (x / est + est) / 2.
d x / est + est
e est + est
f est
g 2.

Even though the argument text extends to the end of the line, the compiler stops once it finds the end of an expression (text after the terminating token is ignored).

When displaying a STRING value, the debugger shows nonprinting characters as <n>, where n is the character's code.

4.46. Displaying Fields: .V {p1, ..., pn}

Display the ADDRESSes and contents of dynamic objects pointed to by the POINTERs pi.

.V p, where p points to a dynamic record or data section, displays all the data fields of p's record or data section. If p points to a data section, both interface and outer variables are shown. If p points to a dynamic ARRAY, the declaration of the ARRAY is displayed as well as its contents; the declaration includes the type, name, and bounds of the ARRAY. You can use A to display just the ARRAY elements, or to display only some of the ARRAY elements.

p may be a (LONG) INTEGER or (LONG) BITS constant that the user has determined to be the ADDRESS of a dynamic ARRAY, dynamic record, or data section; e.g.:

.V 'H123456

is valid if 'H123456 is the ADDRESS of a dynamic object. Dynamic objects may be moved during memory management, so that constant ADDRESSes may become invalid.

p may be a classified POINTER or ADDRESS of the form q:c, where q is a POINTER or ADDRESS expression and c the name of a CLASS; q need not point at a dynamic object in this case, but may point at any accessible memory. The memory at q is displayed as if it were a record of the specified CLASS. Alignment of fields in the CLASS must comply with the processor's requirements, if any; e.g., if the processor requires LONG REAL to be aligned on an 8-byte boundary, then all LONG REAL fields of c must fall on an 8-byte boundary with respect to c, or the command will fail. $p1 and $p2 are not updated by this form of p. A (LONG) INTEGER or (LONG) BITS constant cannot be used as q, since the compiler would complain; e.g., instead of .V 'H1234:cls, use .V cva('H1234L):cls.

When using the display-oriented interface there is an especially convenient way to examine the records in a linked list. Suppose the records are linked through a POINTER field link, and the first record is pointed to by a POINTER variable p. Start with .Vp, which prints all the fields of the first record. To view the next record, move the cursor to the value displayed for link, e.g., 'H123456L, and give the command .V<eol>. This uses the current word ('H123456L) as the POINTER to the next record. Any number of additional records can be viewed this way.

Use V r to display the contents of an inplace record r and V ary to display the contents of an inplace ARRAY ary.

4.47. Watching Variables: +W expression

The +W expression command maintains a display of the expression expression. It updates the display automatically each time the debugger gains control. This is useful, e.g., if you want to see the value of the same variable every time you hit a breakpoint.

The variant +.W expression treats expression as a POINTER and shows the contents of the dynamic object to which expression points instead of the value of expression itself.

Note that the outer and interface variables of the current MODULE are displayed if the D debugger option is in effect, and the local variables of the current PROCEDURE are displayed if the F option is in effect, even when there are no watch expressions.

4.47.1. Specifying the Watched Expression

Generally speaking, the watched expression supplied to the +{.}W command can be any expression that would be valid in the debugger's current command context. However, the data section (MODULE instance) and coroutine that are used to evaluate the expression depend on the current debugger context and on whether expression contains a bracketed watch expression specifier, as described below in Section 4.47.1.3. If only one instance of the MODULE in question is ever created and it runs in only one coroutine, the debugger will use that instance and coroutine, so you do not have to worry about the considerations described in the following sections.

4.47.1.1. The Default for Watched Expressions Specified When the Debugger Context Includes a Data Section and PROCEDURE
If the debugger command context includes a data section at the time you give the +{.}W command (e.g., if you have just hit a breakpoint in the context where you want the watched expression to be evaluated), then by default the expression is watched only in that data section. For example, if you are at a breakpoint in (or have walked the call stack to) the INITIAL PROCEDURE of a MODULE SAMPLE, and you specify a command like +W bucketSize, where bucketSize is an outer variable of SAMPLE, bucketSize is watched only for the current data section of SAMPLE. If multiple data sections are created for SAMPLE, the debugger updates the display for the instance of bucketSize in only the data section for which the variable is watched, and ignores the other data sections.

When you specify a watch command, the debugger lets you know what data section(s) the command is associated with:

    SAMPLE.INITIALPROC+w bucketSize<eol>
    
Watching bucketSize

    --
Watched Exprs--
    1. [
SAMPLE('H1AFBF0)] bucketSize  0

Note that the value for the POINTER to the data section ('H1AFBF0) may change during the course of execution if a chunk compaction memory management operation occurs; however, such operations are infrequent.

Whenever the debugger's command context includes a current PROCEDURE, you may include its local variables and parameters in the watched expression.

For example, if the current command context is the PROCEDURE hash in SAMPLE, and hash contains local variables h and i, then the expression may include h and i. Whenever the debugger updates the display of an expression that includes h and i, it displays the values of h and i in the most recent invocation of hash, provided that the most recent invocation is for a data section and coroutine in which the debugger is watching those variables. By default, the debugger watches h and i only for the command context's current data section and current coroutine at the time the watch command is given.

When you specify a watch expression that includes one or more local variables, the debugger displays slightly more information than in the example above:

SAMPLE.HASH+w h + i<eol>
Watching h + i

--
Watched Exprs--
1. [
SAMPLE('H1AFBF0)] bucketSize           131
2. [
MAINSAIL:SAMPLE('H1AFBF0).HASHh + i  34

The text “MAINSAIL:” shows the name of the coroutine in which hash was invoked.

If, later, an additional data section for SAMPLE is created, you can give a command to watch the expressions h + i in hash and the outer variable bucketSize for that data section as well. If the current context is for hash in a data section of SAMPLE at 'H1B2440, you can do:

SAMPLE.HASH+w bucketSize<eol>
Watching bucketSize

--
Watched Exprs--
1. [
SAMPLE('H1AFBF0)] bucketSize  131
2. [
SAMPLE('H1B2440)] bucketSize  211

SAMPLE.HASH+w h + i<eol>
Watching h + i

--
Watched Exprs--
1. [
SAMPLE('H1AFBF0)] bucketSize           131
2. [
SAMPLE('H1B2440)] bucketSize           211
3. [
MAINSAIL:SAMPLE('H1B2440).HASHh + i  -8

Note that at most one value is shown in the watched expression list for h + i: the value in the most recent invocation of hash, and only if hash was invoked in an appropriate data section and coroutine, i.e., those for which h + i is watched. If hash calls itself recursively, and you want to see the values for h and i in all invocations of hash on the stack, you can use the debugger's .SS (show stack) command.

4.47.1.2. The Default for Watched Expressions Specified When the Debugger Context Includes a MODULE But No Data Section and PROCEDURE
Sometimes, the current debugger command context does not include a data section and PROCEDURE, but does include a MODULE. This is the situation, for example, if you invoke the debugger (while the MODULE SAMPLE is not executing) and issue the command M sample. The debugger then has a MODULE context for SAMPLE, but since no data section has yet been created for SAMPLE, it cannot have a data section or PROCEDURE context.

In this situation, without giving a bracketed watch expression specifier (see Section 4.47.1.3) in the watched expression, you can refer to outer variables of SAMPLE, but not to local variables of a PROCEDURE (since there is no PROCEDURE context). In this case, outer variables of SAMPLE are watched for every data section of SAMPLE, not just for one data section. For example:

SAMPLE+w bucketSize<eol>
Watching bucketSize

--
Watched Exprs--
1. [
SAMPLEbucketSize  <unavailable>

When bucketSize is watched in every data section for SAMPLE, the display of watched variables always includes at least one entry for bucketSize, even when no data section exists for SAMPLE; when no data section exists, a message appears saying bucketSize is unavailable. When multiple data sections for SAMPLE exist, the value of bucketSize is shown for each data section:

--Watched Exprs--
1. [
SAMPLE('H1AFBF0)] bucketSize  131
   [
SAMPLE('H1B2440)] bucketSize  211

The two data sections are shown under the same watch expression number (namely, 1).

4.47.1.3. Overriding the Defaults: Bracketed Watch Expression Specifiers in Watched Expressions
Prefixing a bracketed watch expression specifier to the watched expression lets you override the defaults described above in the following ways:

The syntax for a bracketed watch expression specifier is:

[{coroutineName:}moduleName{.procedureName}]

i.e., square brackets surrounding a MODULE name, optionally preceded by a coroutine name followed by a colon, and optionally followed by a period and a PROCEDURE name.

Watched expressions that include a bracketed watch expression specifier are always watched for all data sections (present and future) of that MODULE, regardless of the current context.

If the PROCEDURE name is omitted, then the expression cannot include local variables, but may refer to any outer variable of the MODULE:

MAINDEBUG+w [sample]bucketSize<eol>
Watching bucketSize

--
Watched Exprs--
1. [
SAMPLEbucketSize          <unavailable>

The coroutine name, if present, is ignored when the watched expression contains no local variables.

If the PROCEDURE name is included, the expression may include local variables for the specified PROCEDURE. In this case, the expression is watched for every data section of the MODULE:

MAINDEBUG+w [sample.hash]h + i<eol>
Watching h + i

--
Watched Exprs--
1. [
SAMPLE.HASHh + i          <unavailable>

As with expressions containing only outer variables, when an expression containing local variables is watched for every data section, a message is displayed when no frame for the PROCEDURE in question exists.

It is not possible to watch an expression containing local variables of more than one PROCEDURE, or non-interface outer variables of more than one MODULE, since there is no context in which such an expression could be compiled.

If a coroutine name is included in the specifier for an expression containing local variables, the expression is watched only when the PROCEDURE is invoked in that coroutine. For example, if the current context is the PROCEDURE hash in the MODULE SAMPLE, and the current coroutine is named MAINSAIL, and there is no invocation of hash in the coroutine anotherCoroutine, then the invocation in anotherCoroutine is reported as unavailable:

SAMPLE.HASH+w [MAINSAIL:sample.hash]h + i<eol>
Watching h + i

--
Watched Exprs--
1. [
MAINSAIL:SAMPLE('H1EBFF0).HASHh + i    9

h _ 
length(s); i _ h MIN 4; }j _ 1;
SAMPLE.HASH+w [anotherCoroutine:sample.hash]h + i<eol>
Watching h + i

--
Watched Exprs--
1. [
MAINSAIL:SAMPLE('H1EBFF0).HASHh + i    9
2. [
ANOTHERCOROUTINE:SAMPLE.HASHh + i      <unavailable>

4.47.2. Watched Expressions and Multiple Coroutines

In a program with multiple coroutines, watch expressions containing local variables are evaluated for every coroutine unless a coroutine was given in the specifier. Thus, if both the root coroutine, MAINSAIL, and another coroutine, COROUTINE1, have an active invocation to SAMPLE.hash, then after the command +W [sample.hash]h + i, the display might look like:

--Watched Exprs--
1. [
MAINSAIL:SAMPLE('H1B2440).HASHh + i    17
   [
COROUTINE1:SAMPLE('H1AFBF0).HASHh + i  24

Both local variables are shown under the same number, because both are displayed by the same watch expression.

The data section and coroutine for each expression are displayed so that you can keep track of which value is current where.

4.47.3. When the Debugger Considers Two Watch Expressions to be the Same

If you are already watching an expression for one or more particular data sections of a MODULE and you give a command to watch the same expression in all data sections of the MODULE or vice versa, the debugger treats the two commands as separate, and maintains two entries on the watched expression list. It also maintains two entries for expressions that are not textually identical (case is distinguished), so that if you watch BUCKETsize and bucketSIZE, you get two different entries.

The debugger considers two watch list entries the same only when the entries are textually the same and specified for the same data sections (and coroutines, if applicable). The debugger does not add a new entry to the watch list when you give a watch command that specifies the same information as an existing entry.

4.48. Breaking When a Value Changes: +W:C expression, +W:Z expression, +W:N expression

Adding the modifier :C, :Z, or :N to the +{.}W command allows you to break when some condition becomes TRUE of a watched expression. In addition to displaying the value of the specified expression whenever the debugger gains control, the debugger evaluates the expression periodically while your program is running, and breaks whenever the value satisfies the condition given by the modifier.

By default, the time at which the program evaluates the conditions is whenever control enters a debuggable PROCEDURE. However, if any of the watched expressions with a break condition contains local variables for the current PROCEDURE, the debugger checks the conditions more frequently, after the execution of each statement. You can change the default so that the debugger always evaluates break conditions after each statement by giving the OP s command, and revert to the default with -OP s (see Section 4.32).

If you specify the . modifier (i.e., +.W:), meaning display the dynamic object to which expression points instead of expression itself, the condition still applies only to expression itself, not to the fields of the object to which expression points. However, the display shows the fields, not expression.

4.48.1. +W:C expression

This command breaks when expression has a value different from the last time it was checked, that is, when the expression has changed (“C” stands for “change”).

4.48.2. +W:Z expression

This command breaks when expression has a Zero value. For example, if expression is a BOOLEAN expression, the debugger breaks whenever it checks expression and expression is FALSE.

4.48.3. +W:N expression

This command breaks when expression has a non-Zero value. For example, if expression is a BOOLEAN expression, the debugger breaks whenever it checks expression and expression is TRUE.

4.48.4. Changing the Break Condition Associated with a Watch Expression

Sometimes you may want to change the break condition associated with a watch expression. To do this without retyping the entire expression, you can use the syntax:

+W:conditionCharacter:expressionNumber

where expressionNumber is the number of the watched expression as displayed in the watched expressions list, and conditionCharacter is either C, Z, N, or -. If conditionCharacter is a letter, the break condition is changed to the one specified by the letter; if -, the break condition is removed from the watch expression.

For example, +W:Z:2 means change the break condition associated with watch expression #2 to break-on-Zero. +W:-:1 means remove any break condition associated with the first watch expression.

4.49. Stop Watching Variables: -W n1,n2,...

The command -W can be used to cancel a +W or +.W command.

The argument is a list of watch expression numbers, separated by commas. The numbers are the same ones shown in the watched expression list.

After a watch expression is deleted, the number of higher-numbered expressions on the list is decremented, so that the numbers always start at 1 and are contiguous.

4.50. Stop Watching All Variables: -!W

The command -!W cancels all +W and +.W commands currently in effect.

4.51. Examining Memory: {+}XM expression{,type1,type2,...}

Examine consecutive memory locations.

expression is a POINTER, ADDRESS, or CHARADR expression, or a (LONG) INTEGER or (LONG) BITS constant. Memory locations are displayed starting at the memory address given by expression, and initially proceeding towards higher addresses. If expression is a CHARADR, it is rounded down to the next lower data-type-aligned address before use.

The command enters a subcommand mode with a “:” prompt. Responses may include any of the subcommands listed in Table 4–5.

Table 4–5. XM Subcommands
t display type t = bo,i,li,r,lr,b,lb,s,a,c,p
t display characters
x display hex dump, 16 bytes per line (or 32 bytes on a 64-bit machine), along with corresponding characters
xw like x, except on little-endian machines, where each group of bytes is displayed from highest address to lowest (i.e., as LONG BITS values) instead of vice versa
- reverse direction
<eol> display same type in same direction
? show this list
x (x is any text that does not match another subcommand) exit subcommand mode and execute x as debugger commands. Use a space character for x to exit subcommand mode and not execute any debugger commands

Each time a value is displayed, the memory address is automatically incremented (default) or decremented by the size of the examined value. The subcommand t causes memory to be examined as characters. Five LONG INTEGERs' worth of text is displayed each time (typically 40 or 80 characters, depending on the machine).

The abbreviations in Table 4–5 can also appear in a comma-separated list on the command line after the address at which to start examining memory. If so, the specified commands are executed before entering subcommand mode.

The +XM form of the command displays PDF (portable data format) values for those data types that have a PDF representation (see Chapter 26 of the MAINSAIL Language Manual for a description of PDF).

4.52. Executing Statements: XS s1;...;sn {END}

The XS command compiles and executes the statements si. The si must be MAINSAIL statements valid in the current command context.

The END is required if additional debugger commands are to be given on the same line as the XS command. It is a terminating token for the compiler. Alternatively, the si may be enclosed in brackets: XS [s1;...;sn].

XS with no arguments uses @1 as the default argument; i.e., the current line supplies the argument text.

Example 4–6. Use of the XS Command
XS i := 0

assigns 0 to i.

XS cRead(sEND v s[1 TO 5]

removes the first char of s, then displays its first five characters.

XS FOR i := 1 UPTO 10 DO ttyWrite(a[i],eol)

displays elements 1 through 10 of a. The A command could be used instead.

XS@ffoo.msl

compiles and executes statements in the file foo.msl.


previous   next   top   complete contents   complete index   framed top   this page unframed

MAINDEBUG User's Guide, Chapter 4