All Manuals > LispWorks® User Guide and Reference Manual > 3 The Debugger

3.4 REPL debugger commands

This section describes commands specific to the debugger. In the debugger, you can also do anything that you can do in the top-level loop including evaluation of forms and the standard listener commands.

Upon entry to the debugger the implicit current stack frame is set to the top of the execution stack. The debugger commands allow you to move around the stack, to examine the current frame, and to leave the debugger. The commands are all keywords, and as such case-insensitive, but are shown here in lower case for clarity.

You can get brief help listing these commands by entering :? at the debugger prompt.

3.4.1 Backtracing

A backtrace is a list of the stack frames starting at the current frame and continuing down the stack. The backtrace thus displays the sequence by which the functions were invoked, starting with the most recent. For instance:

CL-USER 10 > (defun function-1 (a b c)
               (function-2 (+ a b) c))
FUNCTION-1
 
CL-USER 11 > (defun function-2 (a b)
               (function-3 (+ a b)))
FUNCTION-2
 
CL-USER 12 > (defun function-3 (a) (/ 3 (- 111 a)))
FUNCTION-3
 
CL-USER 13 > (function-1 1 10 100)
 
Error: Division-by-zero caused by / of (3 0)
  1 (continue) Return a value to use
  2 Supply new arguments to use
  3 (abort) return to level 0.
  4 return to top loop level 0.
  5 Destroy process.
 
Type :c followed by a number to proceed
 
CL-USER 14 : 1 > :bq 10
 
SYSTEM::DIVISION-BY-ZERO-ERROR <- / <- FUNCTION-3
<- SYSTEM::*%APPLY-INTERPRETED-FUNCTION <- FUNCTION-2
<- SYSTEM::*%APPLY-INTERPRETED-FUNCTION <- FUNCTION-1
<- SYSTEM::*%APPLY-INTERPRETED-FUNCTION <- SYSTEM::%INVOKE <- SYSTEM::%EVAL
 
CL-USER 15 : 1 > 

In the above example the command to show a quick backtrace was used (:bq). Instead of showing each stack frame fully, this only shows the function name associated with each of the call frames. The number 10 following :bq specifies that only the next ten frames should be displayed rather than continuing to the bottom of the stack.

:b Debugger command

:b &optional verbose m

This is the command to obtain a backtrace from the current frame. It may optionally be followed by :verbose, in which case a fuller description of each frame is given that includes the values of the arguments to the function calls. It may also be followed by a number (m), specifying that only that number of frames should be displayed.

:bq Debugger command

:bq m

This produces a quick backtrace from the current position. Only the call frames are included, and only the names of the associated functions are shown. If the command is followed by a number then only that many frames are displayed.

3.4.2 Moving around the stack

On entry to the debugger the current frame is the one at the top of the execution stack. There are commands to move to the top and bottom of the stack, to move up or down the stack by a certain number of frames, and to move to the frame representing an invocation of a particular function.

:> Debugger command

This sets the current frame to the one at the bottom of the stack.

:< Debugger command

This sets the current frame to the one at the top of the stack.

:p Debugger command

:p [ m | fn-name | fn-name-substring ] 

By default this takes you to the previous frame on the stack. If it is followed by a number then it moves that number of frames up the stack. If it is followed by a function name then it moves to the previous call frame for that function. If it is followed by a string then it moves to the previous call frame whose function name contains that string.

:n Debugger command

:n [ m | fn-name | fn-name-substring ]

Similar to the above, this goes to the next frame down the stack, or m frames down the stack, or to the next call frame for the function fn-name, or to the next call frame whose function name contains fn-name-substring.

3.4.3 Miscellaneous commands

:v Debugger command

This displays information about the current stack frame. In the case of a call frame corresponding to a compiled function the names and values of the function's arguments are shown. Closure variables (either from an outer scope or used by an inner scope) and special variables are indicated by {Closing} or {Special} as in this session:

CL-USER 32 > (compile (defun foo (*zero* one two)
                        (declare (special *zero*))
                        (list (/ one *zero*) #'(lambda () one) two)))
FOO
NIL
NIL
 
CL-USER 33 > (foo 0 1 2)
 
Error: Division-by-zero caused by / of (1 0).
  1 (continue) Return a value to use.
  2 Supply new arguments to use.
  3 (abort) Return to level 0.
  4 Return to top loop level 0.
 
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
 
CL-USER 34 : 1 > :n foo
Call to FOO
 
CL-USER 35 : 1 > :v
Call to FOO {offset 114}
  *ZERO*  {Special} : 0
  ONE  {Closing}    : 1
  TWO               : 2
 
CL-USER 36 : 1 >

For an interpreted function the names and values of local variables are also shown.

If the value of an argument is not known (perhaps because the code has been compiled for speed rather than other considerations), then it is printed as the keyword :dont-know.

:l Debugger command

:l [ m  | var-name | var-name-substring ]

By default this prints a list of the values of all the local variables in the current frame. If the command is followed by a number then it prints the value of the m'th local variables (counting from 0, in the order shown by the :v command). If it is followed by a variable name var-name then it prints the value of that variable (note that the same effect can be achieved by just entering the name of the variable into the Listener). If it is followed by a string var-name-substring then it prints the value of the first variable whose name contains var-name-substring.

In all cases, * is set to the printed value.

:error Debugger command

This reprints the message which was displayed upon entry to the current level of the debugger. This is typically an error message and includes several continuation options.

:cc Debugger command

:cc &optional var

This returns the current condition object which caused entry to this level of the debugger. If an optional var is supplied then this must be a symbol, whose symbol-value is set to the value of the condition object.

:ed Debugger command

This allows you to edit the function associated with the current frame. If you are using TAGS, you are prompted for a TAGS file.

:all Debugger command

:all &optional flag

This option enables you to set the debugger option to show all frames (if flag is non-nil), or back to the default (if flag is nil). By default, flag is t.

See also set-debugger-options.

:lambda Debugger command

This returns the lambda expression for an anonymous interpreted frame. If the expression is not known, then it is printed as the keyword :dont-know.

:func Debugger command

:func &optional disassemble-p

This returns (and sets * to) the function object of the current frame. This is especially useful for the call frame of functions that are not the symbol function of some symbols, for example closures and method functions.

If disassemble-p is true, :func first disassembles the function, and then returns it and sets *. The default value of disassemble-p is nil.

:func is applicable only in call frames.

:lf Debugger command

This command prints symbols from other packages corresponding to the symbol that was called, but could not be found in the current package. If there is only one such symbol then it is also offered as restarts when you first enter the debugger.

NEW 21 > (display-message)
 
Error: Undefined operator DISPLAY-MESSAGE in form (DISPLAY-MESSAGE).
  1 (continue) Try invoking DISPLAY-MESSAGE again.
  2 Return some values from the form (DISPLAY-MESSAGE).
  3 Try invoking CAPI:DISPLAY-MESSAGE with the same arguments.
  4 Set the symbol-function of DISPLAY-MESSAGE to the symbol-function of CAPI:DISPLAY-MESSAGE.
  5 Try invoking something other than DISPLAY-MESSAGE with the same arguments.
  6 Set the symbol-function of DISPLAY-MESSAGE to another function.
  7 Set the macro-function of DISPLAY-MESSAGE to another function.
  8 (abort) Return to top loop level 0.
 
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
 
NEW 22 : 1 > :lf
Possible candidates are (CAPI:DISPLAY-MESSAGE)
CAPI:DISPLAY-MESSAGE
 
NEW 23 : 1 > 

3.4.4 Leaving the debugger

You may leave the debugger either by taking one of the continuation options initially presented, or by explicitly specifying values to return from one of the frames on the stack.

:a Debugger command

This selects the :abort option from the various continuation options that are displayed when you enter the current level of the debugger.

:c Debugger command

:c &optional m

If this is followed by a number then it selects the option with that number, otherwise it selects the :continue option.

:ret Debugger command

:ret value 

This causes value to be returned from the current frame. It is only possible to use this command when the current frame is a call frame. Multiple values may be returned by using the values function. So to return the values 1 and 2 from the current call frame, you could type:

:ret (values 1 2)

:res Debugger command

:res m

Restarts the current frame. If m is nil, you are prompted for new arguments which should be entered on one line, separated by whitespace. If m is true or is not supplied, the original arguments to the frame are used.

:top Debugger command

Aborts to the top level of the debugger. A synonym is :a :t.

3.4.5 Example debugging session

This section presents a short interactive debugging session. It starts by defining a routine to calculate Fibonacci Numbers, and then erroneously calls it with a string.

  1. First, define the fibonacci function shown below in a listener.
    (defun fibonacci (m)
      (let ((fib-n-1 1)
            (fib-n-2 1)
            (index 2))
        (loop
         (if (= index m) (return fib-n-1))
         (incf index)
         (psetq fib-n-1 (+ fib-n-1 fib-n-2)
                     fib-n-2 fib-n-1))))
    
  2. Next, call the function as follows.
    (fibonacci "turtle")
    

    The system generates an error, since cl:= expects its arguments to be numbers, and displays several continuation options, so that you can try to find out how the problem arose.

  3. Enter :bb at the debugger prompt to obtain a full backtrace.

    Notice that the problem is in the call to fibonacci.

    You should have passed the length of the string as an argument to fibonacci, rather than the string itself.

  4. Attempt to calculate this value now, by typing the following form at the debugger prompt.
    (legnth "turtle")
    

    You intended to call fibonacci with the length of the string, but entered length incorrectly. This takes you into the second level of the debugger. Note that the continuation options from your entry into the top level of the debugger are still displayed, and are listed after the new options. You can select any of these options.

  5. Enter :a to abort one level of the debugger.
  6. Enter :error to remind yourself of the original error that you need to handle. You need to fix the value passed as the second argument to fibonacci.
  7. Enter :n fibonacci to move to the stack frame for the call to fibonacci.
  8. Enter :v to display variable information about this stack frame:
    Interpreted call to FIBONACCI:
      M       : "turtle"
      INDEX   : 3
      FIB-N-2 : 1
      FIB-N-1 : 2
    

    You need to set the value of the variable m to be the length of the string "turtle", rather than the string itself.

  9. Enter this form:
    (setq m (length "turtle"))
    

    In order to get the original computation to resume using the new value of m, you still need to handle the original error.

  10. Enter :error to remind yourself of the original error condition.

    You can handle this error by returning nil from the call to cl:=, which is the result that would have been obtained if m had been correctly set initially.

  11. Enter :c to invoke the continue restart, which in this case requires you to return a value to use.
  12. When prompted for a form to be evaluated, enter nil.

    This causes execution to continue as desired. Notice that the correct result 8 is returned.


LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:18