previous next top complete contents complete index framed top this page unframed
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.
Some debugger A commands
that might be used on ary and their results
are:
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);
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] = 3A 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] = 3A 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] = 6A 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] = 9A 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,j) THEN RETURN
^ ^
EF baz(s,i) THEN gak(i,j);
^ ^
getNextI(i,j) END;
^ ^
The rules for placing breakpoints on something other than a non-empty statement are as follows:
PROCEDURE foo;
BEGIN
...
END;
^
When a single step returns from a PROCEDURE, it breaks at the caller's final END if the call was the last thing executed in the PROCEDURE. The final END of a PROCEDURE is not reached if the PROCEDURE executes a RETURN statement or is aborted by an exception.
DO UNTIL NOT p := p.link;
^ ^
FOR i := 1 UPTO 10 DOB proc1(args1); proc2(args2) END;
^
[ ] ;
^
PROCEDURE foo;;
^
BEGIN IF foo THEN bar ELSE baz END
^ ^ ^ ^
A breakpoint placed on an END is reached only if control flows through the END. For example, the ENDs below are not reached, since a DONE is always executed first:
DOB IF foo THENB bar; DONE END # not reached
^ ^ ^ ^ ^
EB baz; DONE END; # not reached
^ ^ ^
END; # not reached
^
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]
{+}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:
{+}B@ module1.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:
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 ddi1; STRING dds1; POINTER(c) ddp1; 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:
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 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.
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.:
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.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.
.F 'H123456,f
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) * j) END;
RETURN(h MOD bucketsize) END;
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
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"
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
{+}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:
T@ module1.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.
When you specify a watch command, the
debugger lets you know what data
section(s) the command is associated
with:
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:
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:
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.
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:
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:
The two data sections are shown under
the same watch expression number
(namely, 1).
The syntax for a bracketed watch
expression specifier is:
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:
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:
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:
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.
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.
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.
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.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.
SAMPLE.INITIALPROC: +w bucketSize<eol>
Watching bucketSize
--Watched Exprs--
1. [SAMPLE('H1AFBF0)] bucketSize 0
SAMPLE.HASH: +w h + i<eol>
Watching h + i
--Watched Exprs--
1. [SAMPLE('H1AFBF0)] bucketSize 131
2. [MAINSAIL:SAMPLE('H1AFBF0).HASH] h + i 34
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).HASH] h + i -8
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.
SAMPLE: +w bucketSize<eol>
Watching bucketSize
--Watched Exprs--
1. [SAMPLE] bucketSize <unavailable>
--Watched Exprs--
1. [SAMPLE('H1AFBF0)] bucketSize 131
[SAMPLE('H1B2440)] bucketSize 211
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:
[{coroutineName:}moduleName{.procedureName}]
MAINDEBUG: +w [sample]bucketSize<eol>
Watching bucketSize
--Watched Exprs--
1. [SAMPLE] bucketSize <unavailable>
MAINDEBUG: +w [sample.hash]h + i<eol>
Watching h + i
--Watched Exprs--
1. [SAMPLE.HASH] h + i <unavailable>
SAMPLE.HASH: +w [MAINSAIL:sample.hash]h + i<eol>
Watching h + i
--Watched Exprs--
1. [MAINSAIL:SAMPLE('H1EBFF0).HASH] h + 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).HASH] h + i 9
2. [ANOTHERCOROUTINE:SAMPLE.HASH] h + 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).HASH] h + i 17
[COROUTINE1:SAMPLE('H1AFBF0).HASH] h + i 24
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.
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.
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
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.
| 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(s) END 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. |
MAINDEBUG User's Guide, Chapter 4