Swat, a BCPL-oriented debugger
Swat is a debugger meant to be used with the Alto operating system.
While many of its features are BCPL oriented, it can be used on any
Alto program. This document describes version 31 of Swat, which is
compatible with Operating System versions 17 and greater.
1. History
Swat was designed and built by Jim Morris and Allen Brown during the
summer of 1973. Bob Sproull added the error file mechanism and parity
error logging during 1976. Peter Deutsch rewrote the command processor
and added the command file facility in early 1977. David Boggs
renovated the program, adding mulitple proceed break points and
TeleSwat, and Ed Taft added the help facility in late 1978. Everyone
agrees that the human interface is awful. Each person who has worked
on Swat has added several more obscure commands while they were at it.
2. How it works
Swat is an external debugger: with the exception of a small piece of
'resident' code in your address space, it lives in a separate space.
When Swat is invoked, the resident saves your state on the file Swatee,
and swaps in Swat. References to your memory from within Swat go to
the Swatee file. When you tell Swat to proceed, it saves itself on the
file Swat, swaps you (the Swatee) in and resumes you. Your state at
the time Swat got control is displayed in a window at the bottom of the
screen. "AC0", "PC", etc are built-in symbols with which you can
manipulate it.
3. Invocation
Swat may be applied to any program running under the operating system
after it has been installed (see Installation below). There are six
ways of getting its attention:
(1) Hold down the <control> and <left-shift> keys and then
press the <Swat> key.
(2) Have your program execute the op-code 77400B.
(3) Invoke the Resume/S command (see below).
(4) Boot the file Dumper.Boot, normally by booting with the "DU"
keys depressed.
------------
Copyright Xerox Corporation 1982
SWAT April 10, 1982 2
(5) Type <programName>/! to the Alto command processor.
(6) Call the function CallSwat. Up to 2 arguments will be printed
as BCPL strings. Thus CallSwat("No more memory")
4. Commands
The command scanner has suffix action symbols, all of which are control
characters (e.g. ↑C). "n" is any BCPL expression (see Expressions
below), "$" is escape except where noted, "cr" means carriage return,
"lf" means line-feed. You can abort whatever Swat is doing at any time
and get back to the top level command scanner by pressing the <Swat>
key.
4.1. Help facility
Most debuggers have a terse and obscure command syntax, and Swat is no
different. In fact it's worse since Swat doesn't use the DDT debugger
dialect (it uses a subdialect of an MIT debugger dialect--where Allen
Brown grew up). Typing "?" prompts you for a command character which
Swat looks up in the file "Swat.help". Responding "?" to its prompt
gives you a small table of contents for the rest of the help file.
4.2. Displaying cells
address↑D prints the contents of n in decimal
address↑I prints the contents of n as two 8-bit bytes
address↑N prints the contents of n as an instruction
address↑O prints the contents of n in octal
address↑S prints the contents of n as a pair of characters
address↑V prints address in octal and decimal
The last cell printed is called the open cell. ↑O, ↑D, ↑I, ↑N, or ↑S
alone re-prints the open cell in the appropriate format. If you wish
to print out a number of cells, beginning with the open cell, say n$↑D,
n$↑I, etc. The last cell printed becomes the open cell.
lf (↑J) opens and prints the contents of the next cell (after the
open one) in the same mode.
↑W opens and prints the cell before the open cell.
↑A opens and prints the cell pointed at by the open cell.
↑E opens and prints the cell at the effective address of the
open cell.
The last cell that was opened by any command except LF or ↑W is called
the last open cell. Often you are stepping through code, follow a
pointer with ↑E or ↑A, look around, decide it's not interesting and
wish to resume where you were before following the pointer. You can
get back to last open cell plus or minus one by:
$lf ($↑J) open and print last open cell+1.
SWAT April 10, 1982 3
$cr ($↑M) open and print last open cell.
$↑W open and print last open cell-1
4.3. Changing cells
The contents of the open cell (if there is one) may be changed by
typing an expression for the new value followed by a cr, lf or ↑W. A$B
followed by cr, lf or ↑W stores A lshift 8 + B into the open cell.
4.4. Searching
n↑= searches from the open cell+1 for a cell whose contents is
n. Prints and opens that cell.
n$↑= searches from the open cell+1 for a cell whose effective
address is n. Prints and opens that cell.
A search terminates at the end of memory (location 176777b -- the I/O
area is not touched) and can take quite a while: abort by hitting
<swat>. The argument for a search command is defaulted to the last
value searched for if omitted.
4.5. Running the program
↑P resumes the program, i.e. proceeds.
address↑G resumes the program at address, i.e. goes there.
<procName>$<e1>$...$<en>↑C calls the BCPL procedure "procName" with
parameters <e1>,...,<en> (n<6). If you wish one of the
arguments to be a BCPL-format string, merely enclose it in
quotes. Thus OpenFile$"Com.Cm."↑C will return a stream on
the file. AC2 is assumed to contain a legal stack frame
pointer and 'procName' will allocate a new frame on top of
it. Often AC2 is not valid (e.g., Swat interrupted the
program in the middle of allocating a frame), and calling a
procedure at this point may not work. Most of the time Swat
can detect this and warn you.
↑U restores the user's screen. Hitting the <swat> key brings
back Swat.
↑K forces the user program to abort, just as if you had typed
<left-shift><swat> while it was running.
4.6. Break Points
A Break point can be referred to by its address or by the index
assigned by Swat when the break point was set. When printing or
deleting a breakpoint, Swat reaches out into the user's address space
to check that the break is still there.
address↑B sets a break at address
↑B set a break at the open cell
SWAT April 10, 1982 4
0$address↑B deletes the break at address
proceedCnt$address↑B sets a multiple-proceed break point at address.
The breakpoint will take effect when it has been hit
proceedCnt times, and then it will be deleted.
Passing through a multiple proceed break point
without stopping takes about 200 us.
index$↑B deletes the break with index index
0$$↑B deletes all breaks
$$↑B prints all broken locations.
$↑P removes the current break and proceeds.
address$$↑P sets a one-shot break point at address and then
proceeds. A one-shot break point is one that is
removed after it is hit.
stackIndex$↑P sets a break at a BCPL return point in the stack
somewhere and proceeds from the present break. The
parameter n specifies the frame number, where the
most recent (top) frame is 0. Thus if ↑T typed out
0:GOO+56 1:HAM+5, 1$↑P would set a break at HAM+6
and proceed.
4.7. Stack Study
See Chapter 10 of the BCPL manual and section 4.8 of the Operating
System manual for the details of a BCPL stack.
↑T prints the current PC and all return addresses in the call
stack (symbolically), until an inconsistency in the stack
(usually signaling its end) is encountered. After each
return address is listed the parameters passed to the
procedure that will be returned to. "2: 43752 137 0 Foo+45-
-(14 177777)" means the 2nd most recent frame at 43752, of
length 137 is procedure Foo in bank 0, called with arguments
14 and -1 (fine point: 14 and 177777 are the first two local
variables in Foo's frame, which Foo could have modified
before Swat was called, in which case they won't be the
values passed at call time).
n↑T traces a stack beginning with the frame at location n.
index↑F prints the parameters of the nth latest stack frame and sets
the pseudo symbol "$" (not escape) equal to the base of that
frame. If ↑T displayed something like 0:FOO+3,
1:BLETCH+10,... Type 1↑F to see the parameters that were
passed to BLETCH. $ is set to the base of BLETCH's frame
(i.e., $ points at the frame's back link: the first local
variable is in $+4.
SWAT April 10, 1982 5
4.8. Symbol table
↑Y prompts you for the name of a symbol file. Type the name of
the subsystem that's running. If it can't find a file with
the name you typed, Swat appends ".syms" to it and looks up
the resulting file name before reporting failure. If BLDR
created the file FOO.RUN it also created FOO.SYMS, which
gives the locations of all the static names. Only statics
can be used in Swat. There are permanent built-in symbols
for the interesting page-1 and high memory locations, BCPL
runtime routines, and the user's state variables (AC0-3, PC,
etc.).
4.9. Save/Restore
See 'Resumable files' below for more details:
↑L prompts you for a file name on which it saves the current
Swatee.
↑Q prompts you for a file name which it installs as the current
Swatee.
4.10. The Spy Facility
The spy can be used to estimate where the time is going on a percentage
basis. It samples the PC every 30-milliseconds.
(1) Type ↑X and Swat will display how much user memory it needs for
the metering code and tables.
(2) Probe around to find a block of storage of the required size, and
tell Swat by typing
n↑X
where n is the first word of the block.
(3) Proceed to run the program.
(4) Once Swat gets control again you can type
$↑X
to display the results and terminate the spying activity, or
$$↑X
to display the results so far and continue the spying.
4.11. Miscellaneous
$↑Y Prompts for the name of a (text) file from which Swat
commands should be taken. Reading will continue across
"proceeds" from breakpoints, but will be aborted if Swat is
invoked by the keyboard (<control><left-shift><swat>) or by
the standard break-point trap (77400B).
SWAT April 10, 1982 6
$$↑Y Puts Swat into TeleSwat server mode. The keyboard is
ignored: to regain local control hit the <Swat> key. For
more on TeleSwat see the sections on Address Spaces and
TeleSwat.
n↑R Prints the value of R or S register n. You must have a RAM
for this to work.
$↑R Prints all of the R and S registers.
$$↑Z Repeats the message that was displayed when Swat was
invoked. This is sometimes useful if an error message has
scrolled away as a result of poking around.
$↑Z Prints statistics on the symbol table and virtual memory
caches. This is mostly of interest to Swat maintainers.
4.12. Address Spaces
↑Z prompts for the target address space. Swat can treat any file
created by OutLd, any bank of memory, and any host in the internet
(with the host's cooperation) as the Swatee: the address space into
which you peer with Swat. The syntax for address spaces is:
filename this is 'Swatee' for normal debugging, but can be
any file created by OutLd (sysOut files (↑L) are in
this category), or Dumper.
Bank0 Swat itself.
Bank1...3 the extended memory banks. These are only legal on
AltoII XMs. No check is made that a bank actually
exists. If it doesn't, or if it hasn't been
written into since the Alto was powered up, you are
likely to get parity errors.
[host] a host that implements the server half of the
TeleSwat protocol (usually another Swat). [host]
can be either a name: [Boggs], or an internet
address: [3#241#]. The square brackets are
required: this is how Swat decides that you mean a
[host] rather than a file.
4.13. Examples
X↑O↑D prints the value of X in octal, then decimal.
func+3↑N lf lf prints instructions 3, 4, and 5 of func.
1↑O7 sets location 1 to 7.
label↑B sets a break at label
7562↑B sets a break at location 7562B
SQRT$16↑C calls the (user) function SQRT (the returned value is
printed)
SWAT April 10, 1982 7
label+3↑G transfers to the third instruction after label.
0↑T prints the PC
0↑F prints the parameters of the most recent call
2↑F prints the parameters of the third most recently
called procedure; then
$↑O prints the saved stack pointer (frame!0)
$+1↑0 prints the return address (frame!1)
$+6↑O prints the first local (if the procedure has 2
parameters).
5. Expressions
Expressions are as in BCPL with the following exceptions
' means exclusive OR
\ means REMAINDER
| means LSHIFT for positive arguments, RSHIFT for negative
~ means NOT
A string of digits is interpreted as octal unless suffixed by a "."
$ (not escape) is the base of the last opened stack frame (see ↑F
above). Initially it is the last frame.
↑<static name>, "↑" followed immediately by a static name, means use
the address of the static, not its value, even if it is a procedure- or
label-type static.
. is the last opened cell
PC is the address of the cell containing the user PC. This is the
address at which Swat will resume Swatee when you say ↑P.
AC1,...,AC3 are the addresses of the user's accumulators.
CRY is the address of the user's carry bit.
INT = on = non zero if interrupts where on when the Swat trap happened.
No function calls in expressions.
No relational operators (e.g. EQ)
No conditional expressions
No lv operator (well...see ↑<static name> above)
SWAT April 10, 1982 8
5.1. Examples
.-1↑O prints the cell before the currently open cell.
.+1↑O is like line-feed.
AC1↑O6 sets AC1 to 6
PC↑O72
↑P is like 72↑G
PC↑O lf lf lf lf prints the PC and the AC's
The conventions for expression evaluation are not truly BCPL-like.
"F↑0" will print the first instruction of F if BLDR thought it was a
procedure or label, but print the contents of static cell F if BLDR
thought it was a variable. If F started life as a variable, but had a
procedure assigned to it you must call it by "@F↑C" instead of "F↑C".
6. Resumable Files
The file Swatee is a snapshot of a running program and can be saved for
subseqent resumption or examination. You can create a copy of Swatee
by using COPY or, if you are in Swat, typing ↑L and giving a file name.
This copies Swatee to the named file and appends some information
internal to Swat -- the current symbol table and break point data.
There are several ways to restart resumable files:
1) Press the boot button while holding down the keys for the
file.
2) Type the command (it is interpreted by the Exec)
RESUME file
If "file" is omitted Swatee is assumed.
RESUME/S file
writes file onto Swatee and invokes Swat.
3) While in Swat, type ↑Q and give a file name. The file is
copied onto Swatee and Swat's internal information is
restored to whatever was saved by the ↑L command that
created the file. If the file was created in some way
other than ↑L, the internal information is reset to an
empty state.
7. TeleSwat
Swat implements a simple Pup protocol, TeleSwat, by which it can treat
a machine anywhere in the internet as the Swatee (with the consent and
cooperation of the other machine). The Swatee is made receptive to
SWAT April 10, 1982 9
control from the network by typing $$↑Y. The controlling Swat's
attention is directed at it by specifying the Swatee's network address
as the target virtual memory (see the ↑Z command). When you tell the
Swatee to proceed (↑P, ↑G, ↑U), you loose control: your Swat starts
probing the Swatee once per second, but if the Swatee never returns,
you must get help from someone at the other end. Each time a packet is
sent, the cursor is inverted to let you know something is happening.
Executing the opcode 77412b is equivalent to CallSwat(string1 [],
string2 []) followed by $$↑Y.
8. Desperation Debugging
If the resident is broken so you can't use <Left-Shift><Control><Swat>
to get to Swat to see what went wrong, then you are desperate. Press
the boot button while holding down the keys for the file Dumper.Boot
(the OS and InstallSwat conspire to make this be "DU" normally). This
writes the existing memory onto Swatee with the exception of page 0
which is lost (Dumper lands in page 0 when you boot it). Also the
display word (420b) is cleared. Finally, Swat is invoked.
9. Error Message Printing
Swat contains some facilities to aid in printing error messages.
Because the Swat resident is almost always present when a program is
running, an error message can be printed by simulating a Swat "break,"
and letting the Swat program decipher the error specification and print
a reasonable message.
If Swat is invoked by the 77403b trap instruction, the contents of AC0
are taken to be a pointer to a BCPL string for a file name; AC1 is a
pointer to table [ errCode%ClearBit; p1; p2; p3; p4.... ], where
errCode (0 le errCode le 32000.) is an error code, the p's are
"parameters," and ClearBit is either 100000b (clear the Swat screen
before printing the message) or 0 (do not clear).
The intended use is with a BCPL procedure like:
let BravoError(code, p1, p2, nil, nil, nil) be
[
code = code%UserClearScreenBit
(table [ 77403B; 1401B ])("bravo.errors", lv code)
// do a "finish" here if fatal error
]
The error messages file is a sequence of error messages, searched in a
dumb fashion. An error message is:
a. An unsigned decimal error number (digits only)
b. Followed optionally by:
C Always clear the screen before printing the message
M (see below)
L Log the error via the Ethernet.
c. Followed by a <space>.
d. Followed by text for the message, including carriage returns, etc.
If you wish to refer to a parameter, give:
SWAT April 10, 1982 10
$
followed by a digit to specify the parameter number (1-9)
followed optionally by "!<offset>" which treats parameter as a
number, adds offset to it, and sets parameter to the
contents of the resulting address (i.e. a vector ref).
followed by a character to say how to print the parameter:
O = octal
D = decimal
S = string (parameter is pointer to BCPL string)
(example: $1D will print parameter 1 in decimal)
The quote character is <escape>.
e. Followed by $$.
After the message is typed, if M was specified, the message "Type
<control>K to kill, or <control>P to proceed." is typed out.
10. Parity Error Information
When the Alto detects a parity error, Swat is usually invoked to print
a message about the details of the error. It then attempts to "log"
the error with an Ethernet server responsible for keeping maintenance
information. If the server is not operating, or if your Alto is not
connected to an Ethernet with such a server, simply strike the <Swat>
key, and the familiar "#" will appear.
In many cases, you will want to continue execution of your program
after a parity error is detected. Simply type <control>P to Swat.
11. Installation
Get the file InstallSwat.Run. Then invoke it to create Swat (the
debugger), Swatee (the swap file for the user's memory image), and
Dumper.Boot (the desperation debugger invoker). InstallSwat.Run may be
deleted after it has been run once. Use the Exec's BootKeys command to
discover the keys to depress for Dumper.Boot; normally they are "DU".
InstallSwat.run is the Swat program. When invoked it, it hooks up to
the current operating system, initializes itself, and then OutLds all
of core including the OS (suitably Junted and slightly patched) onto
the file Swat.
There are two global switches, /D and /X. /D installs Swat in "debug"
mode. In this mode Swat goes into TeleSwat looking at bank 0 (i.e.
Swat itself) when anything untoward happens, such as finishing,
trapping, calling Swat, calling SysErr, or getting a parity error. If
debug mode is not set, Swat will try to recover from these
catastrophies rather than go into TeleSwat. When in debug mode,
hitting the <Swat> key does not force control back to the top level,
and <left-shift><control><Swat> forces Swat into TeleSwat.
/X installs Swat in "extended memory" mode, for debugging IFS and other
systems built on the IFS base. In this mode, Swat is prepared to
SWAT April 10, 1982 11
follow address pointers which lead to inter-bank jump instructions
(code statics and stack return addresses).
12. Caveats
1. Swat has about 1k of resident code in high memory. This code is
not changed when new subsystems come in. Therefore re-boot if it seems
to be in a bad state. Swat can get itself into a bad state too.
SYSINing (↑Q) Swatee is a very effective general purgative; ignore the
warning message - its doing exactly what you want it to. If all else
fails, make sure you have a clean copy of the OS, and then reinstall
Swat by running InstallSwat.run.
2. Instructions 77400B - 77777B are used by Swat. The actions of some
of these (e.g. 77401B) are published; you get what you deserve if you
use the unpublished ones. Location 567B (in the trap vector) is used.
3. Interrupt channel 8 (00400B) is used by the resident for keyboard
interrupts (getting to swat via a <control><left-shift><swat> key
combination).
4. A program fetching data from a broken location will get 774xxB.
5. While most interrupt routines are reasonably polite and always
resume the interrupted code where it left off, the politeness of Swat's
keyboard interrupt is entirely in the hands of the person at the
controls. If he re-starts by saying ↑P, all goes well; but he may say
↑G or ↑C. Therefore
a) You should disable the keyboard interrupt by anding 77377B into
453B during critical sections of code (once they are
debugged).
b) Expect occasional anomalies after ↑C or ↑G is used.
6. The mappings between symbols and addresses are naive about BCPL's
block structure.
a) If a symbol is defined twice or more you get the lowest
address.
b) An address is mapped into a procedure name plus a displacement
for symbolic type out (e.g. for ↑T). If procedure A is
defined inside procedure B, most of B's addresses will be
typed as if they were A's.
7. If a disk error prevents swapping, the offending disk control block
and label are displayed in the "boot-lights" manner.
8. Locations 700b through 707b are used to save the machine state
before each swap.
9. If a file created on a different disk is resumed by booting,
invoking Swat may not work because Swat and Swatee may not reside at
the same disk addresses on the different disks. This difficulty does
not occur if the Exec's RESUME command is used, since it will fix up
the addresses before resuming it.