25.2. Debugging Utilities [sec_25-1-2]

25.2.1. Function DISASSEMBLE
25.2.2. Function EXT:UNCOMPILE
25.2.3. Function EXT:SHOW-STACK
25.2.4. Function DOCUMENTATION
25.2.5. Function DESCRIBE
25.2.6. Macro TRACE
25.2.7. Function INSPECT
25.2.8. Macro TIME
25.2.9. Function ED
25.2.10. Functions APROPOS & APROPOS-LIST
25.2.11. Function DRIBBLE
25.2.11.1. Scripting and DRIBBLE

List of Examples

25.1. Identifying Individual Calls in TRACE

25.2.1. Function DISASSEMBLE

Platform Dependent: UNIX platform only.
DISASSEMBLE can disassemble to machine code, provided that GNU gdb is present. In that case the argument may be a EXT:SYSTEM-FUNCTION, a FFI:FOREIGN-FUNCTION, a special operator handler, a SYMBOL denoting one of these, an INTEGER (address), or a STRING.

25.2.2. Function EXT:UNCOMPILE

The function EXT:UNCOMPILE does the converse of COMPILE: (EXT:UNCOMPILE function) reverts a compiled function (name), that has been entered or loaded in the same session and then compiled, back to its interpreted form.

25.2.3. Function EXT:SHOW-STACK

The function EXT:SHOW-STACK is called by the backtrace command.

It prints to *STANDARD-OUTPUT* and accepts 3 optional arguments:

It can used to find out what all the threads are up to:

(LOOP :with out = *STANDARD-OUTPUT* :for thread :in (MT:LIST-THREADS) :do
   (FORMAT out "===~A===~;" thread)
   (MT:THREAD-INTERRUPT thread :function
     (LAMBDA () (LET ((*STANDARD-OUTPUT* out)) (EXT:SHOW-STACK 1 3)))))

25.2.4. Function DOCUMENTATION

No on-line documentation is available for the system functions (yet), but see Section 25.2.5, “Function DESCRIBE.

25.2.5. Function DESCRIBE

When CUSTOM:*BROWSER* is non-NIL, and CUSTOM:CLHS-ROOT returns a valid URL, DESCRIBE on a standard Common Lisp symbol will point your web browser to the appropriate [Common Lisp HyperSpec] page.

Also, when CUSTOM:*BROWSER* is non-NIL, and CUSTOM:IMPNOTES-ROOT returns a valid URL, DESCRIBE on symbols and packages documented in these implementation notes will point your web browser to the appropriate page.

To do this, DESCRIBE will retrieve the appropriate tables from CUSTOM:CLHS-ROOT and CUSTOM:IMPNOTES-ROOT on the first relevant invocation. These operations are logged to CUSTOM:*HTTP-LOG-STREAM*.

Function CUSTOM:CLHS-ROOTFunction CUSTOM:CLHS-ROOT is defined in config.lisp. By default it looks at (EXT:GETENV "CLHSROOT") and CUSTOM:*CLHS-ROOT-DEFAULT*, but you may redefine it in config.lisp or RC file. The return value should be a STRING terminated with a "/", e.g., http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/ or /usr/doc/HyperSpec/. If the return value is NIL, the feature is completely disabled. CUSTOM:*CLHS-ROOT-DEFAULT* is initialized in config.lisp based on the --hyperspec passed to the top-level configure script when CLISP was built.

Function CUSTOM:IMPNOTES-ROOTFunction CUSTOM:IMPNOTES-ROOT is defined in config.lisp. By default it looks at (EXT:GETENV "IMPNOTES") and CUSTOM:*IMPNOTES-ROOT-DEFAULT*, but you may redefine it in config.lisp or RC file. The return value should be a STRING terminated with a "/", e.g., http://clisp.org/impnotes/, or the path to the monolithic page, e.g., http://clisp.org/impnotes.html or /usr/doc/clisp/impnotes.html. If the return value is NIL, the feature is completely disabled.

25.2.6. Macro TRACE

(TRACE function-name ...) makes the functions function-name, ... traced. Each function-name should be either a function name or a LIST (function-name &KEY :SUPPRESS-IF :MAX-DEPTH :STEP-IF :BINDINGS :PRE :POST :PRE-BREAK-IF :POST-BREAK-IF :PRE-PRINT :POST-PRINT :PRINT), where

:SUPPRESS-IF form
no trace output as long as form is true
:MAX-DEPTH form
no trace output as long as (> *trace-level* form). This is useful for tracing functions that are use by the tracer itself, such as PRINT-OBJECT, or otherwise when tracing would lead to an infinite recursion.
:STEP-IF form
invokes the stepper as soon as form is true
:BINDINGS ((variable form)...)
binds variables to the result of evaluation of forms around evaluation of all of the following forms
:PRE form
evaluates form before calling the function
:POST form
evaluates form after return from the function
:PRE-BREAK-IF form
goes into the break loop before calling the function if form is true
:POST-BREAK-IF form
goes into the break loop after return from the function if form is true
:PRE-PRINT form
prints the values of form before calling the function
:POST-PRINT form
prints the values of form after return from the function
:PRINT form
prints the values of form both before calling and after return from the function

In all these forms you can access the following variables:

EXT:*TRACE-FUNCTION*
the traced function itself
EXT:*TRACE-ARGS*
the arguments to the function
EXT:*TRACE-FORM*
the function/macro call as form
EXT:*TRACE-VALUES*
after return from the function: the list of return values from the function call

and you can leave the function call with specified values by using RETURN.

TRACE and UNTRACE are also applicable to functions (SETF symbol) and to macros, but not to locally defined functions and macros.

Trace output

TRACE prints this line before evaluating the form: trace level. Trace: form and after evaluating the form it prints: trace level. Trace: function-name ==> result where trace level is the total nesting level.

If you want the TRACE level to be indicated by the indentation in addition to the printed numbers, set CUSTOM:*TRACE-INDENT* to non-NIL. Initially it is NIL since many nested traced calls will easily exhaust the available line length.

Examples

Example 25.1. Identifying Individual Calls in TRACE

Suppose the trace level above is not enough for you to identify individual calls. You can give each call a unique id and print it:

(defun f0 (x)
  (cond ((zerop x) 1)
        ((zerop (random 2)) (* x (f0 (1- x))))
        (t (* x (f1 (1- x))))))
⇒ F0
(defun f1 (x)
  (cond ((zerop x) 1)
        ((zerop (random 2)) (* x (f0 (1- x))))
        (t (* x (f1 (1- x))))))
⇒ F1
(defvar *f0-call-count* 0)
⇒ *F0-CALL-COUNT*
(defvar *id0*)
⇒ *ID0*
(defvar *cc0*)
⇒ *CC0*
(defvar *f1-call-count* 0)
⇒ *F1-CALL-COUNT*
(defvar *id1*)
⇒ *ID1*
(defvar *cc1*)
⇒ *CC1*
(trace (f0 :bindings ((*cc0* (incf *f0-call-count*))
                      (*id0* (gensym "F0-")))
           :pre-print (list 'enter *id0* *cc0*)
           :post-print (list 'exit *id0* *cc0*))
       (f1 :bindings ((*cc1* (incf *f1-call-count*))
                      (*id1* (gensym "F1-")))
           :pre-print (list 'enter *id1* *cc1*)
           :post-print (list 'exit *id1* *cc1*)))
;; Tracing function F0.
;; Tracing function F1.
⇒ (F0 F1)
(f0 10)
1. Trace: (F0 '10)
(ENTER #:F0-2926 1)
2. Trace: (F1 '9)
(ENTER #:F1-2927 1)
3. Trace: (F0 '8)
(ENTER #:F0-2928 2)
4. Trace: (F1 '7)
(ENTER #:F1-2929 2)
5. Trace: (F1 '6)
(ENTER #:F1-2930 3)
6. Trace: (F1 '5)
(ENTER #:F1-2931 4)
7. Trace: (F1 '4)
(ENTER #:F1-2932 5)
8. Trace: (F0 '3)
(ENTER #:F0-2933 3)
9. Trace: (F1 '2)
(ENTER #:F1-2934 6)
10. Trace: (F0 '1)
(ENTER #:F0-2935 4)
11. Trace: (F1 '0)
(ENTER #:F1-2936 7)
(EXIT #:F1-2936 7)
11. Trace: F1 ==> 1
(EXIT #:F0-2935 4)
10. Trace: F0 ==> 1
(EXIT #:F1-2934 6)
9. Trace: F1 ==> 2
(EXIT #:F0-2933 3)
8. Trace: F0 ==> 6
(EXIT #:F1-2932 5)
7. Trace: F1 ==> 24
(EXIT #:F1-2931 4)
6. Trace: F1 ==> 120
(EXIT #:F1-2930 3)
5. Trace: F1 ==> 720
(EXIT #:F1-2929 2)
4. Trace: F1 ==> 5040
(EXIT #:F0-2928 2)
3. Trace: F0 ==> 40320
(EXIT #:F1-2927 1)
2. Trace: F1 ==> 362880
(EXIT #:F0-2926 1)
1. Trace: F0 ==> 3628800
⇒ 3628800
*f0-call-count*
⇒ 4
*f1-call-count*
⇒ 7

25.2.7. Function INSPECT

The function INSPECT accepts a keyword argument :FRONTEND, which specifies the way CLISP will interact with the user, and defaults to CUSTOM:*INSPECT-FRONTEND*.

Available :FRONTENDs for INSPECT in CLISP

:TTY
The interaction is conducted via the *TERMINAL-IO* stream. Please use the help command to get the list of all available commands.
:HTTP

A window in your Web browser (specified by the :BROWSER keyword argument) is opened and it is controlled by CLISP via a SOCKET:SOCKET-STREAM, using the HTTP protocol. You should be able to use all the standard browser features.

Since CLISP is not multitasking at this time, you will not be able to do anything else during an INSPECT session. Please click on the quit link to terminate the session.

Please be aware though, that once you terminate an INSPECT session, all links in all INSPECT windows in your browser will become obsolete and using them in a new INSPECT session will result in unpredictable behavior.

The function INSPECT also accepts a keyword argument :BROWSER, which specifies the browser used by the :HTTP front-end and defaults to CUSTOM:*INSPECT-BROWSER*.

The function INSPECT binds some pretty-printer variables:

VariableBound to
*PRINT-LENGTH*CUSTOM:*INSPECT-PRINT-LENGTH*
*PRINT-LEVEL*CUSTOM:*INSPECT-PRINT-LEVEL*
*PRINT-LINES*CUSTOM:*INSPECT-PRINT-LINES*

User variable CUSTOM:*INSPECT-LENGTH* specifies the number of sequence elements or slots printed in detail when a sequence or a structure or a CLOS object is inspected.

25.2.8. Macro TIME

The timing data printed by the macro TIME includes:

The macro EXT:TIMES (mnemonic: TIME and Space) is like the macro TIME: (EXT:TIMES form) evaluates the form, and, as a side effect, outputs detailed information about the memory allocations caused by this evaluation. It also prints everything printed by TIME.

25.2.9. Function ED

The function ED calls the external editor specified by the value of (EXT:GETENV "EDITOR") or, failing that, the value of the variable CUSTOM:*EDITOR* (set in config.lisp). If the argument is a function name which was defined in the current session (not loaded from a file), the program text to be edited is a pretty-printed version (without comments) of the text which was used to define the function.

25.2.10. Functions APROPOS & APROPOS-LIST

The search performed by APROPOS and APROPOS-LIST is case-insensitive.

Variable CUSTOM:*APROPOS-DO-MORE*You can make APROPOS print more information about the symbols it found by setting CUSTOM:*APROPOS-DO-MORE* to a list containing some of :FUNCTION, :VARIABLE, :TYPE, and :CLASS or just set it to T to get all of the values.

Variable CUSTOM:*APROPOS-MATCHER*You can make APROPOS and APROPOS-LIST be more flexible in their search by setting CUSTOM:*APROPOS-MATCHER* to a FUNCTION of one argument, a pattern (a STRING), returning a new FUNCTION of one argument, a SYMBOL name (also a STRING), which returns non-NIL when the symbol name matches the pattern for the purposes of APROPOS. When CUSTOM:*APROPOS-MATCHER* is NIL, SEARCH is used. Some modules come with functions which can be used for CUSTOM:*APROPOS-MATCHER*, e.g., REGEXP:REGEXP-MATCHER, POSIX:FNMATCH-MATCHER, PCRE:PCRE-MATCHER.

25.2.11. Function DRIBBLE

If DRIBBLE is called with an argument, and dribbling is already enabled, a warning is printed, and the new dribbling request is ignored.

Dribbling is implemented via a kind (but not a recognizable subtype) of TWO-WAY-STREAM, named EXT:DRIBBLE-STREAM. If you have a source bidirectional STREAM x and you want all transactions (input and output) on x to be copied to the target output STREAM y, you can do

(DEFVAR *loggable* x)
(SETQ x (MAKE-SYNONYM-STREAM '*loggable*))
(DEFUN toggle-logging (&OPTIONAL s)
  (MULTIPLE-VALUE-BIND (source target) (dribble-toggle *loggable* s)
    (WHEN (STREAMP source) (SETQ *loggable* source))
    target))
(toggle-logging y)start logging
...
(toggle-logging)finish logging
...
(toggle-logging y)restart logging
...
(toggle-logging)finish logging
(CLOSE y)
(EXT:DRIBBLE-STREAM stream)
When stream is a EXT:DRIBBLE-STREAM, returns two values: the source and the target streams. Otherwise returns NIL.
(EXT:DRIBBLE-STREAM-P stream)
When stream is a EXT:DRIBBLE-STREAM, returns T, otherwise returns NIL.
(EXT:DRIBBLE-STREAM-SOURCE stream)
When stream is a EXT:DRIBBLE-STREAM, returns its source stream, otherwise signals a TYPE-ERROR.
(EXT:DRIBBLE-STREAM-TARGET stream)
When stream is a EXT:DRIBBLE-STREAM, returns its target stream, otherwise signals a TYPE-ERROR.
(EXT:MAKE-DRIBBLE-STREAM source target)
Create a new EXT:DRIBBLE-STREAM.
(EXT:DRIBBLE-TOGGLE stream &OPTIONAL pathname)
When stream is a EXT:DRIBBLE-STREAM and pathname is NIL, writes a dribble termination note to the stream's target STREAM and returns stream's source and target STREAMs; when stream is not a EXT:DRIBBLE-STREAM and pathname is non-NIL, creates a new EXT:DRIBBLE-STREAM, dribbling from stream to pathname, writes a dribble initialization note to pathname, and return the EXT:DRIBBLE-STREAM (the second value is the target STREAM); otherwise WARN that no appropriate action may be taken. pathname may be an open output STREAM or a pathname designator. See above for the sample usage. See also src/dribble.lisp in the CLISP source tree.

25.2.11.1. Scripting and DRIBBLE

DRIBBLE works by operating on *TERMINAL-IO*, thus is does not work when CLISP acts as a script interpreter (see Section 32.6.2, “Scripting with CLISP).

Traditionally, Common Lisp implementations set *STANDARD-INPUT*, *STANDARD-OUTPUT*, and *ERROR-OUTPUT* to a SYNONYM-STREAM pointing to *TERMINAL-IO*, and CLISP is no exception. Thus changing *TERMINAL-IO* to a dribble stream affects all standard i/o.

On the other hand, when CLISP acts as a script interpreter, it adheres to the UNIX <stdio.h> conventions, thus *STANDARD-INPUT*, *STANDARD-OUTPUT*, and *ERROR-OUTPUT* are normal FILE-STREAMs, and thus are not affected by DRIBBLE (*TERMINAL-IO* - and thus (PRINT ... T) - is still affected). The [ANSI CL standard] explicitly permits this behavior by stating

DRIBBLE is intended primarily for interactive debugging; its effect cannot be relied upon when used in a program.


These notes document CLISP version 2.49.60+Last modified: 2017-11-21