






                        CHAPTER  11


              The Joseph Lister Trace Package




     The Joseph Lister[] Trace package is an important  tool
for the interactive debugging of a Lisp program.  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.

     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 _t_r_a_c_e is made.

(trace [ls_arg1 ...])

     WHERE:   the form of the ls_arg_i is described below.

     RETURNS: a list of the  function  sucessfully  modified
              for  tracing.   If  no  arguments are given to
              _t_r_a_c_e, a list of all functions currently being
              traced is returned.

     SIDE EFFECT: The function definitions of the  functions
                  to trace are modified.


The ls_arg_i can have one of the following forms:


  foo - when foo is entered and exited, the  trace  informa-
       tion will be printed.


  (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 _ith argument to the function
       just called can be accessed as (arg _i).  To leave the
       trace   loop,  just  type  ^D  or  (tracereturn)  and
____________________
9   []_L_i_s_t_e_r, _J_o_s_e_p_h     1st  Baron  Lister  of  Lyme  Regis,
1827-1912; English surgeon: introduced antiseptic surgery.



9The Joseph Lister Trace Package                         11-1







The Joseph Lister Trace Package                         11-2


       execution will continue.  Note that ^D will work only
       on UNIX systems.


  (foo if expression) - when foo is entered and the  expres-
       sion evaluates to non-nil, then the trace information
       will be printed for both exit and entry.  If  expres-
       sion evaluates to nil, then no trace information will
       be printed.


  (foo ifnot expression) -  when  foo  is  entered  and  the
       expression  evaluates to nil, then the trace informa-
       tion will be printed for both  entry  and  exit.   If
       both  if and ifnot are specified, then the if expres-
       sion must evaluate to non nil AND the  ifnot  expres-
       sion  must  evaluate to nil for the trace information
       to be printed out.


  (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.


  (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.


  (foo evalinout expression) - this has the same  effect  as
       (trace (foo evalin expression evalout expression)).


  (foo lprint) - this tells _t_r_a_c_e 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.



          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.


  (foo traceenter  tefunc)  -  this  tells  _t_r_a_c_e  that  the


                                      Printed: July 27, 1983







The Joseph Lister Trace Package                         11-3


       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.


  (foo traceexit txfunc) - this tells _t_r_a_c_e that  the  func-
       tion  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.


  (foo evfcn evfunc) - this tells _t_r_a_c_e 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 evalua-
       tion of  function  foo.   The  argument  list  to  be
       applied will be available as T-arglist.


  (foo printargs prfunc) - this tells _t_r_a_c_e 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
       traceenter function.  Specifying the option lprint is
       just  a simple way of changing the printargs function
       to the level printer.


  (foo printres prfunc) - this tells _t_r_a_c_e 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 traceexit function.
       Specifying the option lprint changes printres to  the
       level printer.



          You may specify more  than  one  option  for  each
     function traced. For example:


                                      Printed: July 27, 1983







The Joseph Lister Trace Package                         11-4


     (_t_r_a_c_e (_f_o_o _i_f (_e_q _3 (_a_r_g _1)) _b_r_e_a_k _l_p_r_i_n_t) (_b_a_r _e_v_a_l_i_n
     (_p_r_i_n_t _x_y_z_z_y)))

     This tells _t_r_a_c_e to trace two more functions,  foo  and
     bar.   Should  foo be called with the first argument _e_q
     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  expres-
     sions.  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 argu-
     ments  and  the  result  will  be printed.  If you tell
     _t_r_a_c_e to trace a function which is already  traced,  it
     will  first  _u_n_t_r_a_c_e  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 _n_o_t equivalent to the
     preceding call to _t_r_a_c_e for foo:

     (_t_r_a_c_e (_f_o_o  _i_f  (_e_q  _3  (_a_r_g  _1)))  (_f_o_o  _b_r_e_a_k)  (_f_o_o
     _l_p_r_i_n_t))

     In this example, only the last option, lprint, will  be
     in effect.

          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 use-
     ful  if  the  function you are tracing fails after many
     calls to it.  In this case  you  would  tell  _t_r_a_c_e  to
     trace  the function, set $tracemute to t, and begin the
     computation.  When an error occurs  you  can  use  _t_r_a_-
     _c_e_d_u_m_p to print out the current trace frames.

          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  _c_o_n_d  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).

          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.   _T_r_a_c_e  will  do   a
     (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l)  to  insure that the new traced
     definitions it defines are called instead  of  the  old


                                      Printed: July 27, 1983







The Joseph Lister Trace Package                         11-5


     untraced  ones.  You may notice that compiled code will
     run slower after this is done.

(traceargs s_func [x_level])

     WHERE:   if x_level is missing it is assumed to be 1.

     RETURNS: the arguments to the x_level_t_h call to  traced
              function s_func are returned.

(tracedump)

     SIDE EFFECT: the  currently  active  trace  frames  are
                  printed  on  the terminal.  returns a list
                  of functions untraced.

(untrace [s_arg1 ...])

     RETURNS: a list of the functions which were untraced.

     NOTE: if no arguments  are  given,  all  functions  are
           untraced.

     SIDE EFFECT: the old function definitions of all traced
                  functions  are restored except in the case
                  where it appears that the current  defini-
                  tion  of  a  function  was  not created by
                  trace.
























9

9                                      Printed: July 27, 1983



