previous next top complete contents complete index framed top this page unframed
2.1. Compilation
All MODULEs that are to take part
in debugging must be compiled with the
DEBUG compiler option; refer to
Section 4.9 of the MAINSAIL Compiler User's Guide
for details.
The DEBUG compiler option causes
an intmod (intermediate MODULE) to
be generated, in addition to the
objmod (object MODULE). The intmod
includes debugging information such as
symbol tables and tables that relate
code offsets with source file
positions for each MAINSAIL statement.
An intmod can be stored in a separate
file, or in an intlib (intmod
library). Intmods are described in the
Chapter 13 of the MAINSAIL Language Manual.
Intlibs are manipulated with the
utility MODULE INTLIB as described
in Chapter 18 of the MAINSAIL Utilities User's Guide.
2.2. Invocation
The debugger can be invoked explicitly
either from the MAINSAIL executive or
in response to the standard MAINSAIL
error routine prompt. It can also be
invoked automatically if you set the
environment variable
STARTMSLINDEBUGGER on operating
systems that support environment
variables; see
Section 2.2.3.
To invoke the debugger from the MAINSAIL executive, type DEBUG in response to the MAINSAIL * prompt (i.e., run the MODULE DEBUG). To invoke the debugger after an error has occurred, type DEBUG (or enough to make this response unique) to the Error Response: prompt. You can enter the debugger this way even when a fatal error occurs, although continuing execution from a fatal error is not allowed.
Invoking the debugger as the MODULE DEBUG before executing the program to be debugged allows you to prepare for the debug session, e.g., to set breakpoints, and then invoke the program from the debugger (it is said to “run under the debugger”). Invoking the debugger in response to an error message gives you control at the point of the error.
2.2.1. Setting Debugger Options in the Parameter File
You can set some debugger options that
affect the way the debugger behaves in
your parameter file. This facility is
described in detail in
Section 4.32.
2.2.2. Typical Ways to Start a Debugging Session
There are five common ways to begin a
debugging session:
As an easier way to start your program under the debugger, on operating systems that support environment variables (e.g., UNIX and Windows), MAINSAIL examines the environment variable STARTMSLINDEBUGGER at the start of its execution. If the variable has the value 1 (i.e., the string consisting of the digit one), MAINSAIL invokes $debugExec after processing the SUBCOMMANDS specified in the bootstrap and in any v1630.prm files it finds, but before invoking the MODULE specified by COMMANDSTRING, if any. This allows you to set breakpoints in your program at the beginning of its execution. You can then resume execution of your program by issuing the debugger's C command or by quitting the debugger.
The STARTMSLINDEBUGGER environment
variable invokes $debugExec even in
MAINSAIL bootstraps that do not have
COMMANDSTRING set, but is most useful
in conjunction with such bootstraps.
2.3. Finding Intmods
The debugger must be able to find the intmod for each MODULE that is to take part in a debug session. When the debugger needs to find an intmod for some MODULE M, it first searches all open intlibs, then tries to open the file named xxx-int:m, where xxx is the “file abbreviation” for the operating system (typically the same as the standard MAINSAIL abbreviation for the operating system, or the first three characters of that abbreviation; see Section 14.1 of the MAINSAIL Language Manual). For example, the file abbreviation for PA-RISC UNIX is upa; the file the debugger tries to open on that operating system is upa-int:m.
A searchpath is customarily specified during MAINSAIL initialization for file names of the form xxx-int:*, where xxx is the first three letters of the current operating system abbreviation. The searchpath distributed by XIDAK for UPA is:
SEARCHPATH upa-int:* *-upa.int
Thus, on PA-RISC UNIX the debugger tries to obtain the intmod for M from the file m-upa.int if it cannot find it in an open intlib.
The debugger provides the OI (Open Intlib) command for opening intlibs (OI is described in Section 4.30). Also, the MAINEX subcommand OPENINTLIB can be used to open an intlib (MAINEX subcommands can be given at any time by running MODULE SUBCMD). Each intlib that contains an intmod needed during the debug session should be open before the debugger tries to find the intmod. The MAINEX subcommands INTFILE, INTLIB, and INTDEFAULT also provide control over intmod searches, as described in Chapter 14 of the MAINSAIL Language Manual and Table 21–5 of the MAINSAIL Utilities User's Guide.
If you put a needed intmod in an
intlib and forget to open the intlib
before the debugger needs to access
it, the debugger fails to find the
intmod in the default file, so it
issues an error message and prompts
for a new file name or library in
which to look.
2.4. Context
In the debugger, context can
include the following things:
The debugger keeps track of three kinds of context: command context, breakpoint context, and compiler context.
The command context (sometimes also called the debugger context or even just “context” when the meaning is clear) is the context in which most debugger commands are given; for example, commands to examine variables show the values resulting from evaluating the variables in the current command context.
The breakpoint context exists only if the debugger has hit a breakpoint (or has been invoked from a program); it is the context in which the breakpoint was hit (or from which the debugger was invoked). The breakpoint context can be changed only by continuing execution and hitting a new breakpoint.
The compiler context is used by the !D, .I, and .+I commands. This context allows the declaration of an identifier to be displayed even in contexts where an expression containing the identifier could not be evaluated (e.g., a local variable that cannot be evaluated because the PROCEDURE where it is declared has not been invoked. The debugger nonetheless has sufficient information to display the variable's declaration).
The command context does not have to include all the possible context elements; for example, there can be a current MODULE but not a current PROCEDURE. In such a case, commands that require a current PROCEDURE (such as commands that examine local variables) are not valid, but commands that depend only on the current MODULE (such as commands that set breakpoints) are valid. Initially, the command context is empty.
The breakpoint context generally contains either all context elements (if a breakpoint has been reached) or none (if no breakpoint has been reached).
Whenever the debugger obtains control, the command context and breakpoint context are set to be the same: if any debuggable PROCEDURE has been invoked in the current coroutine, the context is set to the breakpoint or point from which the debugger was invoked within that PROCEDURE invocation. If no debuggable PROCEDURE has been invoked within the current coroutine, both command context and breakpoint context are set to be empty.
Changing the file and file position parts of the command context (by using editor or debugger commands that position in the source text) does not change the other parts of the command context. The MODULE, data section, coroutine, PROCEDURE, and iUnit parts of the context are affected by such operations as reaching a breakpoint or by the commands that walk the call or exception stack or change the current coroutine.
You may use file positioning commands to move to a place where a breakpoint can be set, but only if the breakpoint position is in a file used by the current MODULE (i.e., the current MODULE part of the command context). Otherwise, when you attempt to set the breakpoint, the debugger informs you that the file is not one of the files used in the current MODULE.
The compiler context's MODULE context is the same as the MODULE part of the command context. The PROCEDURE context (if any) is the PROCEDURE where the debugger cursor is located; there is no PROCEDURE context if the cursor is outside any PROCEDURE for the current MODULE. Thus, you can see a local variable v of a PROCEDURE p in a MODULE M by setting the MODULE context to M with the M command, moving the cursor into p, and saying !D v.
You can always examine the
declarations of identifiers that are
predefined by MAINSAIL, regardless of
whether or not there is a compiler
context.
2.5. Positions and iUnits
Context can include a position within
a MODULE if the MODULE is
currently executing. Such a position
within a MODULE is usually
specified by positioning the cursor to
the appropriate place in the
MODULE's source text, but it can
also be specified numerically as an
offset in the control section for the
MODULE. Such an offset is called
an iUnit (for “instruction
unit”). iUnits are
displayed when a stack dump is given,
as by the CALLS error response or
the CALLS utility MODULE, and
by certain debugger commands.
Remembering the iUnit of a location of
interest in a MODULE can save you
the effort of positioning the cursor
to that spot in the source text if you
wish to issue a command referring to
that location, because several debugger
commands take an iUnit as an argument.
However, iUnits become
invalid whenever a MODULE is
recompiled, since the offsets of the
instructions corresponding to source
statements may change.
2.6. Breakpoints and Single Stepping
MAINDEBUG provides four commands for
directly controlling and displaying
the execution of MAINSAIL statements:
the B, T, S, and J
commands. Each command causes program
execution to “break” under specified
conditions. When execution breaks,
MAINDEBUG displays a prompt (in the
line-oriented interface) or an editor
message (in the display-oriented
interface) and waits for further
commands.
The B command sets a permanent breakpoint (one at which execution halts each time the breakpoint is reached); the T command sets a temporary breakpoint (one that is removed the next time a break occurs). The S command executes the next MAINSAIL statement, without following execution into PROCEDUREs; the J command executes the next MAINSAIL statement, breaking on the first statement of any debuggable PROCEDURE invoked. The S and J commands therefore act identically if the executed statements do not invoke a debuggable PROCEDURE. See Chapter 4 for the descriptions of these commands.
The C and .C commands are used to continue execution from a breakpoint; see Section 4.6.
The +W (watch variables) command
can be used to cause the program to
break when a variable changes value or
acquires a specified value; see
Section 4.48.
A command line given by the user in
response to the debugger's prompt is a
sequence of debugging commands. All
commands on a line are executed from
left to right unless an error occurs,
in which case commands after the one
in error are not executed.
The debugger's prompt indicates the
current context and has the default
format (use the OP command to
change the prompt format):
The PROCEDURE name is omitted if
there is no PROCEDURE context; if
there is no MODULE context, the
prompt is:
When a breakpoint is taken, or when
the debugger is entered in response to
an error message, the debugger
displays the appropriate line of text
followed by the debugger prompt,
described above, and awaits a debugger
command. The command line must be
terminated with <eol> before any
command on the line is executed.
2.7. Command Interface
The debugger supports two different
user interfaces: line-oriented and
display-oriented. The
display-oriented interface makes
available to the user all the features
of MAINEDIT during a debugging
session. The line-oriented interface
runs even on terminal types for which
no MAINEDIT display MODULE exists.
2.7.1. Line-Oriented Command Interface
The line-oriented command interface
provides debugging commands and a
simple set of read-only line editor
commands, communicating through the
file TTY. It displays short
pieces of the current file in response
to each debugger command. The
debugger's cursor is indicated by a
right curly bracket, },
immediately preceding the current
character. If any command in a command
line changes the cursor position, the
new line and cursor position are
displayed before the prompt for the
next command line.
moduleName.procedureName:
MAINDEBUG:
2.7.2. Display-Oriented Command Interface
The display-oriented command interface
uses MAINEDIT, the MAINSAIL text
editor. This interface provides
debugging commands and full access to
the command structures offered by the
various editor front ends (which
include MAINVI, an emulation of the
UNIX editor vi, and MAINED,
XIDAK's own front end). The output of
the debugger and the debugged program
is captured in a buffer, so that the
user can refer to earlier output at
any time. The MAINEDIT User's Guide
describes MAINEDIT in detail.
Files are displayed on the screen just as they are by MAINEDIT. The editor cursor is used to indicate the current position in a file, rather than the curly bracket cursor of the line-oriented interface. When a command requiring the debugger to position to a particular location is issued, the file containing the specified MODULE is displayed in a window. If the file was not previously in a buffer, a new window is created and the cursor positioned at the beginning of the file. If there was a buffer for the file, then that buffer is used, and the cursor is positioned where it was when last in that buffer.
The display-oriented interface provides immediate feedback when a command is typed. For example, when the debugger command M is issued, the debugger immediately prompts for the MODULE name on the editor message line. MAINEDIT's <abort> key can be used to abort a debugger command before the user has finished typing it in, or to abort a command that is prompting for further input.
In the display interface, when the debugger is given a character or sequence of characters it cannot interpret as a debugger command, it passes the character(s) to the editor (except for line-oriented debugger commands, which the debugger traps and complains about). The editor executes the appropriate commands and returns to the debugger. In particular, editor macros defined for control keys and keypad keys can be used when interacting with the debugger.
When the debugger reads a file into a MAINEDIT buffer or breaks at a statement in a MAINEDIT buffer, the buffer is made read-only, so that it cannot be accidentally altered, and the mode is set to escape mode, as indicated by the E in the status line. In this mode commands are processed by the debugger rather than the editor. To talk to the editor, type the <ecm> (Enter Command Mode) key. In command mode, all editor commands are available, allowing you to examine files, position the cursor, etc. Use MAINED's E command (or the corresponding commands in the other editor front ends) to enter escape mode and talk to the debugger again. A common mistake is to forget whether you are talking to the debugger or editor, and use a command intended for one mode while in the other. Be careful that you are talking to the editor (as shown by the buffer mode letter) when giving an editor command, and talking to the debugger (E mode) when giving a debugger command.
The file for the current buffer is the debugger's current file. When the user changes the current buffer by means of a MAINEDIT command, the debugger's current file is automatically set to be the file for the new buffer. Thus, the use of editor commands to change buffers is nearly equivalent to using the debugger's F command to change files.
A file is brought into a buffer and displayed when a breakpoint is reached or when the DEBUG command is entered in response to an error message. At this point, the debugger is awaiting a command.
To edit a buffer used by the debugger,
remember that read-only mode must
first be turned off for that buffer
(use MAINED's -.Oreadonly<eol>
command to turn off read-only mode for
the current buffer). After a buffer
has been modified, the debugger
positions in the buffer may no longer
correspond to the appropriate text, so
it is recommended not to continue a
debugging session after changing a
buffer containing a part of a
MODULE being debugged.
2.8. Command Syntax
MAINDEBUG commands are divided into
three groups. General and debugging
commands are used to control debugger
operations and are available from both
the line-oriented and display-oriented
interfaces. Editing commands are
provided with the line-oriented
interface to allow files to be
examined. The editing commands are not
available with the display interface,
since the MAINEDIT commands are used
in this case.
Each command consists of one or more base characters, possibly preceded by an integer count (represented in the descriptions as n), dot (.), plus (+), or minus (-), and possibly followed by arguments. If the count is omitted, 1 is assumed. If both count and minus or plus are permitted for a command, it does not matter which comes first. Dot must usually occur immediately before the command character, although sometimes .n introduces a subcount n. The debugger ignores upper and lower case distinctions in command letters. Spaces and tabs are usually ignored except where they play a role as delimiters as described below.
Arguments can usually occur immediately after the command base with no intervening spaces, e.g., both V x and Vx display the value of x.
Optional parts of commands are indicated in curly brackets; e.g., {n}D means the D command can be preceded by a count.
An id argument is used for identifiers
such as MODULE and field names. A
name argument is used for file names
and coroutine names, which need not be
identifiers. For commands that can
take either a MODULE name or a
file name argument, the debugger scans
a name argument rather than an id
argument since it does not know
whether the argument is a file name or
a MODULE name.
The end of count, id, and name
arguments can be determined simply by
scanning the corresponding object from
the argument text. The ends of expr,
dcl, and stmt arguments are determined
by a more complicated scan carried out
by the MAINSAIL compiler as it
compiles the argument text. When it
encounters a “terminating token”,
i.e., a piece of text that cannot be
the continuation of an expression (for
an expr argument), the start of a
declaration or definition (for a dcl
argument), or the start of a statement
(for a stmt argument), it discards the
token and returns to the debugger.
expr and stmt arguments are restricted
as described in Appendix A.
If a command can have more than one
argument, the arguments are usually
separated from one another by either
commas or semicolons as shown in the
individual command descriptions.
In order to allow several commands on
the same command line, a terminator is
usually required to separate (the last
argument of) a command from the next
command. The rules for terminators are
as follows:
A backslash (\) at the end of a
command line serves as a continuation
character to indicate that another
command line is to be read and
concatenated to the end of the first
one. The backslash and <eol> are
discarded, so precede the backslash
with a space if you need white space
to separate the first line from the
second. Any number of continuation
lines may be specified in this manner.
2.8.1. Command Arguments
The different kinds of debugger
arguments are as follows:
count integer id MAINSAIL identifier name text to first space, tab, or semicolon expr MAINSAIL expression dcl MAINSAIL declarations and definitions stmt MAINSAIL statements
2.8.2. Direct Arguments
Most command arguments can be
specified either directly or
indirectly. In the case of a direct
argument, the argument itself appears
on the command line; e.g., V i
displays the value of i.
A direct argument may be enclosed in brackets to indicate explicitly where it ends. For example, if a file name argument has an embedded space, tab, semicolon, or brackets, it must be enclosed in brackets; use:
F[(my file)]
rather than:
F(my file)
since otherwise (my would be used
as the file name. The debugger is
“smart” about finding a matching
right bracket; i.e., it ignores
brackets in STRING constants and
immediately after single quotes ('['
and ']' are the MAINSAIL INTEGER
constants for the character codes of
left and right bracket, respectively).
An unmatched bracket may not otherwise
occur in a bracketed argument.
2.8.3. Indirect Arguments
An indirect argument is a kind of
subcommand that indicates how the text
of the actual argument is to be
obtained. For example V @w
displays the value of the expression
given by the current “word”. The
following indirect arguments
are provided:
| Argument | Get Argument Text From |
|---|---|
| @fs | contents of file named s |
| @l | rest of current line |
| @n | name (from cursor to space, tab, or semicolon) |
| @t | token (MAINSAIL identifier or constant at cursor) |
| @w | word (from cursor to space or tab) |
| @'c | text (from cursor to first occurrence of character c) |
| @n | n lines |
The command letter after the @ can be uppercase or lowercase; e.g., @W is treated the same as @w. s is a file name, c is any character, and n is an integer count. @t allows MAINSAIL identifiers and constants of type BOOLEAN, INTEGER, REAL, and BITS. The identifier or constant starts at the cursor and continues as long as characters are encountered that form a valid identifier or constant. @l takes the remainder of the current line from the current cursor position.
In @fs, s may be a direct or indirect argument; e.g., @f@l uses the contents of the file whose name is given by the remainder of the current line. Enclose s in brackets if it is a direct name that contains a space, tab, or semicolon, e.g., XS@f[foo.msl] to execute statements in a file named foo.msl.
The current line is the line at which the debugger cursor is currently positioned. This line can be in any file, since the F command allows a file to be specified that becomes the current file. In the display interface, the current line is the one on which the editor's cursor is positioned. Thus argument text can be built up using the editor in an arbitrary buffer, then a command issued with an indirect argument that refers to the text. It is often convenient to put the cursor on some output generated by a previous command such as V or .V and use the @w argument to reference that text.
Most arguments can be omitted, in which case an indirect argument is used by default, as shown:
| Type of Omitted Argument | Default Argument |
|---|---|
| expression | @t (identifier or constant) |
| declarations or statements | @1 (current line) |
| all others | @l (rest of current line) |
An indirect argument specifies the argument text, but the actual argument may be just the initial part of the argument text. However, an indirect name argument uses all of the argument text rather than just the part up to a space, tab, or semicolon as for a direct name argument.
An argument is assumed to be omitted
if the end of the command line, or a
comma or semicolon, appears before any
argument text. For example, if the
command list consists of just V
with no arguments, the effect is the
same as V@t, which displays the
value of the current identifier or
constant. Similarly, V ,j,k is the
same as V @t,j,k, which displays
the value of the current identifier or
constant, then j and k.
2.9. Miscellaneous
(LONG) BITS, ADDRESS,
CHARADR, and POINTER values
are displayed in most cases in the
preferred radix of the processor, as
given by the system macro
$preferredRadix.
The H and
.H commands may be used to force
these values to be displayed in
hexadecimal.
The debugger accepts { in place of [ and } in place of ] for all occurrences of [ and ]. No distinction is made; i.e., { may match ] and [ may match }.
MAINDEBUG User's Guide, Chapter 2