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.
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 &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 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.
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.
This sets the current frame to the one at the bottom of the stack.
This sets the current frame to the one at the top of the stack.
: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 [ 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.
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 [ 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.
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 &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.
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 &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.
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 &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.
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 >
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.
This selects the :abort
option from the various continuation options that are displayed when you enter the current level of the debugger.
: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 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 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.
Aborts to the top level of the debugger. A synonym is :a :t
.
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.
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))))
(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.
: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.
(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.
:a
to abort one level of the debugger.: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
.:n fibonacci
to move to the stack frame for the call to fibonacci
.: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.
(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.
: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.
:c
to invoke the continue restart, which in this case requires you to return a value to use.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