xref: /original-bsd/old/lisp/PSD.doc/ch11.n (revision a1c2194a)
Copyright (c) 1980 The Regents of the University of California.
All rights reserved.

%sccs.include.redist.roff%

@(#)ch11.n 6.2 (Berkeley) 04/17/91

." $Header: ch11.n 1.1 83/01/31 07:08:25 jkf Exp $ .Lc The Joseph Lister Trace Package 11 \\$1 - .. .pp The Joseph Lister\*[\(dg\*] Trace package is an important tool for the interactive debugging of a Lisp program. .(f \*[\(dg\*]Lister, Joseph 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 trace is made. .Lf trace "[ls_arg1 ...]" .Wh the form of the ls_argi 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. The ls_argi can have one of the following forms: .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 i). 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 if 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. .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. .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. .pp You may specify more than one option for each function traced. For example: (trace (foo if (eq 3 (arg 1)) break lprint) (bar evalin (print xyzzy))) 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: (trace (foo if (eq 3 (arg 1))) (foo break) (foo lprint)) 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 (sstatus translink nil) 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_levelth 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.