26.1 Trace
The trace facility allows the user to trace some functions. When a function is traced, certain special actions will be taken when it is called, and when it returns. The function trace allows the user to specify this. The trace facility is closely compatible with Maclisp. Although the functions of the trace system which are presented here are really functions, they are implemented as special forms because that is the way Maclisp did it. Alternatively, you can use the trace system by clicking "trace" in the system menu, or by using the "meta-X trace" command in the editor. This allows you to select the trace options from a menu instead of having to remember the following syntax.
trace Special Form
A trace form looks like:
(trace spec-1  spec-2  ...)
A spec may be either a symbol, which is interpreted as a function name, or a list of the form (function-name option-1 option-2 ...) . If spec is a symbol, it is the same as giving the function name with no options. Some options take "arguments", which should be given immediately following the option name.
The following options exist:
:break pred
Causes a breakpoint to be entered after printing the entry trace information but before applying the traced function to its arguments, if and only if pred evaluates to non-nil .
:exitbreak pred
This is just like break except that the breakpoint is entered after the function has been executed and the exit trace information has been printed, but before control returns.
:stepCauses the function to be single-stepped whenever it is called. See the documentation on the step facility below.
:entrycond pred
Causes trace information to be printed on function entry only if pred evaluates to non-nil .
:exitcond pred
Causes trace information to be printed on function exit only if pred evaluates to non-nil .
:cond pred This specifies both exitcond and entrycond together.
:wherein function
Causes the function to be traced only when called, directly or indirectly, from the specified function function . One can give several trace specs to trace , all specifying the same function but with different wherein options, so that the function is traced in different ways when called from different functions.
:argpdl pdl
This specifies a symbol pdl , whose value is initially set to nil by trace . When the function is traced, a list of the current recursion level for the function, the function's name, and a list of arguments is consed onto the pdl when the function is entered, and cdr'ed back off when the function is exited. The pdl can be inspected from within a breakpoint, for example, and used to determine the very recent history of the function. This option can be used with or without printed trace output. Each function can be given its own pdl, or one pdl may serve several functions.
:entryprint form
The form is evaluated and the value is included in the trace message for calls to the function. You can give this option more than once, and all the values will appear, preceded by \\ .
:exitprint form
The form is evaluated and the value is included in the trace message for returns from the function. You can give this option more than once, and all the values will appear, preceded by \\ .
:print form
The form is evaluated and the value is included in the trace messages for both calls to and returns from the function. You can give this option more than once, and all the values will appear, preceded by \\ .
:entry list
This specifies a list of arbitrary forms whose values are to be printed along with the usual entry-trace. The list of resultant values, when printed, is preceded by a \\ to separate it from the other information.
:exit list This is similar to entry , but specifies expressions whose values are printed with the exit-trace. Again, the list of values printed is preceded by \\ .
:arg :value :both nil
These specify which of the usual trace printout should be enabled. If arg is specified, then on function entry the name of the function and the values of its arguments will be printed. If value is specified, then on function exit the returned value(s) of the function will be printed. If both is specified, both of these will be printed. If nil is specified, neither will be printed. If none of these four options are specified the default is to both . If any further options appear after one of these, they will not be treated as options! Rather, they will be considered to be arbitrary forms whose values are to be printed on entry and/or exit to the function, along with the normal trace information. The values printed will be preceded by a // , and follow any values specified by entry or exit . Note that since these options "swallow" all following options, if one is given it should be the last option specified.
If the variable arglist is used in any of the expressions given for the cond, break, entry, or exit options, or after the arg, value, both, or nil option, when those expressions are evaluated the value of arglist will be bound to a list of the arguments given to the traced function. Thus
(trace (foo break (null (car arglist))))
would cause a break in foo if and only if the first argument to foo is nil . arglist should have a colon, but it is omitted because this is the name of a system function and therefore global. Similarly, the variable si:fnvalues will be a list of the resulting values of the traced function. For obvious reasons, this should only be used with the exit option. The trace specifications may be "factored." For example,
(trace ((foo bar) wherein baz value))
is equivalent to 
(trace (foo wherein baz value) (bar wherein baz value))
Since a list as a function name is interpreted as a list of functions, non-atomic function names (see LINK:(fdefine-fun)) are specified as follows:
(trace (:function (:method foo-class bar) :break t))
All output printed by trace can be ground into an indented, readable format, by simply setting the variable sprinter to t . Setting sprinter to nil changes the output back to use the ordinary print function, which is faster and uses less storage but is less readable for large list structures. This is not yet supported. trace returns as its value a list of names of all functions traced; for any functions traced with the wherein option, say (trace (foo wherein bar)) , instead of putting just foo in the list it puts in a 3-list (foo wherein bar) . If you attempt to specify to trace a function already being traced, trace calls untrace before setting up the new trace. It is possible to call trace with no arguments. (trace) evaluates to a list of all the functions currently being traced.
untrace Special Form
untrace is used to undo the effects of trace and restore functions to their normal, untraced state. The argument to untrace for a given function should be what trace returned for it; i.e. if trace returned foo , use (untrace foo) ; if trace returned (foo wherein bar) use (untrace (foo wherein bar)) . untrace will take multiple specifications, e.g. (untrace foo quux (bar wherein baz) fuphoo) . Calling untrace with no arguments will untrace all functions currently being traced.
Unlike Maclisp, if there is an error trace (or untrace ) will invoke 'c shaft you by invoking the error system and give an English message, instead of returning lists with question marks in them. Also, the remtrace function is not provided, since it is unnecessary.
trace-compile-flag Variable
If the value of trace-compile-flag is non-nil , the functions created by trace will get compiled, allowing you to trace special forms such as cond without interfering with the execution of the tracing functions. The default value of this flag is nil .
26.2 The Stepper
The Step facility provides the ability to follow every step of the evaluation of a form, and examine what is going on. It is analogous to a single-step proceed facility often found in machine-language debuggers. If your program is doing something strange, and it isn't obvious how it's getting into its strange state, then the stepper is for you.
26.2.1 How to Get Into the Stepper.
There are two ways to enter the stepper. One is by use of the step function.
step form
This evaluates form with single stepping. It returns the value of form .
For example, if you have a function named foo , and typical arguments to it might be t and 3 , you could say
(step '(foo t 3))
and the form (foo t 3) will be evaluated with single stepping. The other way to get into the stepper is to use the step option of trace (see LINK:(trace-fun)). If a function is traced with the step option, then whenever that function is called it will be single stepped. Note that any function to be stepped must be interpreted; that is, it must be a lambda-expression. Compiled code cannot be stepped by the stepper.
26.2.2 How to Use the Stepper
When evaluation is proceeding with single stepping, before any form is evaluated, it is (partially) printed out, preceded by a forward arrow ( ) character When a macro is expanded, the expansion is printed out preceded by a double arrow ( ) character. When a form returns a value, the form and the values are printed out preceded by a backwards arrow ( ) character; if there is more than one value being returned, an and-sign ( ) character is printed between the values. Since the forms may be very long, the stepper does not print all of a form; it truncates the printed representation after a certain number of characters. Also, to show the recursion pattern of who calls whom in a graphic fashion, it indents each form proportionally to its level of recursion. After the stepper prints any of these things, it waits for a command from the user. There are several commands to tell the stepper how to proceed, or to look at what is happening. The commands are:
Control-N (Next)
Step to the Next thing. The stepper continues until the next thing to print out, and it accepts another command.
SpaceGo to the next thing at this level. In other words, continue to evaluate at this level, but don't step anything at lower levels. This is a good way to skip over parts of the evaluation that don't interest you.
Control-U (Up)Continue evaluating until we go up one level. This is like the space command, only more so; it skips over anything on the current level as well as lower levels.
Control-X (eXit)
Exit; finish evaluating without any more stepping.
Control-T (Type)
Retype the current form in full (without truncation).
Control-G (Grind)
Grind (i.e. prettyprint) the current form.
Control-E (Editor)
Editor escape (enter the Eine editor).
Control-B (Breakpoint)
Breakpoint. This command puts you into a breakpoint (i.e. a read-eval-print loop) from which you can examine the values of variables and other aspects of the current environment. From within this loop, the following variables are available:
step-formwhich is the current form.
step-valueswhich is the list of returned values.
step-valuewhich is the first returned value.
If you change the values of these variables, it will work.
Control-LClear the screen and redisplay the last 10. pending forms (forms which are being evaluated).
Meta-LLike Control-L, but doesn't clear the screen.
Control-Meta-LLike Control-L, but redisplays all pending forms.
? or HelpPrints documentation on these commands.
It is strongly suggested that you write some little function and try the stepper on it. If you get a feel for what the stepper does and how it works, you will be able to tell when it is the right thing to use to find bugs.
26.3 The MAR
The MAR facility allows any word or contiguous set of words to be monitored constantly, and can cause an error if the words are referenced in a specified manner. The name MAR is from the similar device on the ITS PDP-10's; it is an acronym for "Memory Address Register". The MAR checking is done by the Lisp Machine's memory management hardware, and so the speed of general execution when the MAR is enabled is not significantly slowed down. However, the speed of accessing pages of memory containing the locations being checked is slowed down, since every reference involves a microcode trap. These are the functions that control the MAR:
set-mar location cycle-type &optional n-words
The set-mar function clears any previous setting of the MAR, and sets the MAR on n-words words, starting at location . location may be any object. n-words currently defaults to 1, but eventually it will default to the size of the object. cycle-type says under what conditions to trap. :read means that only reading the location should cause an error, :write means that only writing the location should, t means that both should. To set the MAR on the value of a variable, use
(set-mar (value-cell-location symbol ) :write)
clear-mar location cycle-type &optional n-words
This turns off the MAR. Restarting the machine disables the MAR but does not turn it off, i.e. references to the MARed pages are still slowed down. clear-mar does not currently speed things back up until the next time the pages are swapped out; this may be fixed some day.
si:%mar-low Variable
.defvar1 si:%mar-high These two fixnums are the inclusive boundaries of the area of memory monitored by the MAR. The values of these variables live inside the microcode.
mar-mode location cycle-type &optional n-words
(mar-mode) returns a symbol indicating the current state of the MAR. It returns one of:
nilThe MAR is not set.
:readThe MAR will cause an error if there is a read.
:writeThe MAR will cause an error if there is a write.
tThe MAR will cause an error if there is any reference.
Note that using the MAR makes the pages on which it is set considerably slower to access, until the next time they are swapped out and back in again after the MAR is shut off. Also, use of the MAR currently breaks the read-only feature if those pages were read-only. Currently it is not possible to proceed from a MAR trrap, because some machine state is lost. Eventually, most MAR traps will be continuable.