4.2BSD/usr/lisp/ch11.n

." $Header: ch11.n 1.1 83/01/31 07:08:25 jkf Exp $
.Lc The\ Joseph\ Lister\ Trace\ Package 11
.de Tf
.sp 2v
.ti -.5i
\fB\\$1\fP - 
..
.pp
The Joseph Lister\*[\(dg\*] Trace package is an 
important tool for the interactive debugging of a Lisp
program.
.(f
\*[\(dg\*]\fILister, Joseph\fP\ \ \ \ 
1st Baron Lister of Lyme Regis,
1827-1912; English surgeon: introduced antiseptic surgery.
.)f
It allows you to examine selected  calls to a function or functions, and
optionally to stop execution of the Lisp program to examine the values
of variables.
.pp
The trace package is a set of Lisp programs located in the Lisp program 
library (usually in the file /usr/lib/lisp/trace.l).
Although not normally loaded in the Lisp system, the package will
be loaded in when the first call to \fItrace\fP is made.
.Lf trace "[ls_arg1 ...]"
.Wh
the form of the ls_arg\fIi\fP is described below.
.Re
a list of the function sucessfully modified for tracing.
If no arguments are given to 
.i trace ,
a list of all functions currently being traced is returned.
.Se
The function definitions of the functions to trace are modified.
.sp 2v
.in 0
The ls_arg\fIi\fP can have one of the following forms:
.in .75i
.Tf "foo"
when foo is entered and exited, the trace information will be printed.
.Tf "(foo break)"
when foo is entered and exited the trace information will be printed.
Also, just after the trace information for foo is printed upon entry,
you will be put in  a special break loop.
The prompt is `T>' and you may type any Lisp expression, and see its
value printed.
The 
.i i th 
argument to the function just called can be accessed as (arg \fIi\fP).
To leave the trace loop, just type ^D or (tracereturn)
and execution will continue.
Note that ^D will work only on UNIX systems.
.Tf "(foo if expression)"
when foo is entered and the expression evaluates to non-nil, then the
trace information will be printed for both exit and entry.
If expression evaluates to nil, then no trace information will be
printed.
.Tf "(foo ifnot expression)"
when foo is entered and the expression evaluates to nil, then the
trace information will be printed for both entry and exit.
If both \fBif\fP and 
.b ifnot 
are specified, then the 
.b if 
expression must evaluate
to non nil AND the 
.b ifnot 
expression must evaluate to nil for the trace
information to be printed out.
.Tf "(foo evalin expression)"
when foo is entered and after the entry trace information is printed,
expression will be evaluated. 
Exit trace information will be printed when foo exits.
.Tf "(foo evalout expression)"
when foo is entered, entry trace information will be printed.
When foo exits, and before the exit trace information is printed,
expression will be evaluated.
.Tf "(foo evalinout expression)"
this has the same effect as (trace (foo evalin expression evalout expression)).
.Tf "(foo lprint)"
this tells 
.i trace 
to use the level printer when printing the arguments to
and the result of  a call to foo.
The level printer prints only the top levels of list structure. 
Any structure
below three levels is printed as a &.
This allows you to trace functions with massive arguments or results.
.sp 2v
.pp
The following trace options permit one to have greater control over each
action which takes place when a function is traced.
These options are only meant to be used by people who need special hooks
into the trace package.
Most people should skip reading this section.
.in .75i
.Tf "(foo traceenter tefunc)"
this tells 
.i trace 
that the function to be called when foo is entered is 
tefunc.
tefunc should be a lambda of two arguments, the first argument will be 
bound to the name of the function being traced, foo in this case.
The second argument will be bound to the list of arguments to which 
foo should be applied.
The function tefunc should print some sort of "entering foo" message.
It should not apply foo to the arguments, however. 
That is done later on.
.Tf "(foo traceexit txfunc)"
this tells 
.i trace 
that the function to be called when foo is exited is
txfunc.
txfunc should be a lambda of two arguments, the first argument will be
bound to the name of the function being traced, foo in this case.
The second argument will be bound to the result of the call to foo.
The function txfunc should print some sort of "exiting foo" message.
.Tf "(foo evfcn evfunc)"
this tells 
.i trace 
that the form evfunc should be evaluated to get the value
of foo applied to its arguments.  
This option is a bit different from the other special options since evfunc
will usually be an expression, not just the name of a function, and that
expression will be specific to the evaluation of function foo.
The argument list to be applied will be available as T-arglist.
.Tf "(foo printargs prfunc)"
this tells 
.i trace 
to used prfunc to print the arguments  to be
applied to the function foo.
prfunc should be a lambda of one argument.
You might want to use this option if you wanted a print function which could
handle circular lists.
This option will work only if you do not specify your own 
.b traceenter 
function.
Specifying the option 
.b lprint 
is just a simple way of changing the printargs
function to the level printer.
.Tf "(foo printres prfunc)"
this tells 
.i trace 
to use prfunc to print the result of evaluating foo.
prfunc should be a lambda of one argument.
This option will work only if you do not specify your own 
.b traceexit 
function.
Specifying the option 
.b lprint 
changes printres to the level printer.
.sp 2v
.pp
You may specify more than one option for each function traced.  
For example:
.sp 1v
.ti .5i
\fI(trace (foo if\ (eq 3 (arg 1)) break lprint) (bar evalin (print xyzzy)))\fP
.sp 1v
This tells 
.i trace 
to trace two more functions, foo and bar.
Should foo be called with the first argument 
.i eq
to 3, then the entering foo message will be printed with the level printer.
Next it will enter a trace break loop, allowing you to evaluate any 
lisp expressions.
When you exit the trace break loop, foo will be applied to its arguments
and the resulting value will be printed, again using the level printer.
Bar is also traced, and each time bar is entered, an entering bar message
will be printed and then the value of xyzzy will be printed.
Next bar will be applied to its arguments and the result will be printed.
If you tell 
.i trace 
to trace a function which is already traced, it will first
.i untrace 
it.  Thus if you want to specify more than one trace option for
a function, you must do it all at once.
The following is 
.i not 
equivalent to the preceding call to 
.i trace 
for foo:
.sp 1v
\fI(trace (foo if (eq 3 (arg 1))) (foo break) (foo lprint))\fP
.sp 1v.
In this example, only the last option, lprint, will be in effect.
.pp
If the symbol $tracemute is given a non nil value, printing of the 
function name and arguments on entry and exit will be surpressed.
This is particularly useful if the function you are tracing fails
after many calls to it.  In this case you would tell 
.i trace 
to
trace the function, set $tracemute to t, and begin the computation.
When an error occurs you can use
.i tracedump
to print out the current trace frames.
.pp
Generally the trace package has its own internal names for the the lisp
functions it uses, so that you can feel free to trace system functions like
.i cond 
and not worry about adverse interaction with the actions of the trace
package.
You can trace any type of function: lambda, nlambda, lexpr or macro whether
compiled or interpreted and you can even trace array references (however
you should not attempt to store in an array which has been traced).
.pp
When tracing compiled code keep in mind that many function calls are translated 
directly to machine language  or other equivalent  function calls.
A full list of open coded functions is listed at the beginning of the 
liszt compiler source.
.i Trace 
will do a \fI(sstatus\ translink\ nil)\fP to insure that the 
new traced definitions it defines are called instead of the old untraced ones.
You may notice that compiled code will run slower after this is done.
.Lf traceargs "s_func [x_level]"
.Wh
if x_level is missing it is assumed to be 1.
.Re
the arguments to the x_level\fIth\fP call to traced
function s_func are returned.
.Lf tracedump ""
.Se
the currently active trace frames are printed on the terminal.
returns a list of functions untraced.
.Lf untrace "[s_arg1 ...]"
.Re
a list of the functions which were untraced.
.No
if no arguments are given, all functions are untraced.
.Se
the old function definitions of all 
traced functions are restored
except in the case where it appears that 
the current definition of a function was not created by trace.