By now I'm sure all of you have manage to drop into the HLW debugger. You can do something as simple as:
CL-USER 5 > car
Error: The variable CAR is unbound
1 (continue) Try evaluating it again
2 Return a value to use
3 Return a value to set it to
4 (abort) Return to level 0.
5 return to top loop level 0.
Type :c followed by a number to proceed or type :? for other options
CL-USER 12 : 1 >
Note that the Listener's cursor has changed from being 'CL-USER XX >' to
'CL-USER XX : 1 >' .
This means that you have entered the debugger and are at "break level" one.
If you where to type car again you would end up at "break level" two,
'CL-USER XX : 2 >'.
CL-USER 13 : 2 > :a
CL-USER 14 : 1 >
Meaning, if you were to enter ':a' at this point you would drop back
to level one.
It is not uncommon to wander the lab and see people at "break level" 23 or some such. This isn't really a good idea since there is a bunch of stuff on the "Stack" waiting for you to resolve the breaks. Unfortunately, ( or not depending on your point of view) you can type in anything at the break prompt that you could type in at the top level Listener prompt.
HLW's debugger has numerous commands. To get a short listing of the possible commands type ':help' which will produce the following list:
:lf look for symbol
:bug-form Print a bug report form
:bb Print a full backtrace suitable for a bug report
:bb Print a full backtrace suitable for a bug report
:ed Edit the function associated with the frame
:pp Print the source code for this frame
:v Print the current frame
:bq Print a quick backtrace of interesting call frames
:b Printout a backtrace from the current stack
:a Abort up one level
:error Print the error and how to continue
:n Go down the stack
:p Go up the stack
:c Continue from error
:ret Return from frame
:res Restart frame
:trap Cause the debugger to be re-entered on exit from this frame.
:< Go to the top of the stack
:> Go to the bottom of the stack
:cc Gets the current condition object
:all Set the debugger options to show all call frames
:lambda Show the lambda expression for an anonymous interepreted frame
:redo &optional <command identifier>
Redo a previous command, identified by its number or a substring.
:get <variable> <command identifier>
Get a command from the history list and put it in a variable.
:help Produce this list.
:use <new form> <form to replace> &optional <command identifier>
Replace one form with another form in a previous command and redo the command.
:his List the command history.
I'm only going to explain a few commands on this list.
You can choose any item on the list of options the debugger gives you by just typing ':c' and that number at the debugger prompt. For example
1 (continue) Try evaluating it again 2 Return the value of :BAR instead 3 Return a value to use 4 Return a value to set it to 5 (abort) Return to level 2. 6 return to debug level 2. 7 Try evaluating it again 8 Return a value to use 9 Return a value to set it to 10 Return to level 1. 11 return to debug level 1. 12 Try evaluating it again 13 Return a value to use 14 Return a value to set it to 15 Return to level 0. 16 return to top loop level 0. Type :c followed by a number to proceed or type :? for other options CL-USER 12 : 3 >Here I've managed to drop three levels deep into the debugger. If I wished to jump back up to Level 1 , I need only enter a ':c 10 ' at the prompt. Entering ':c 16' would go to Lisp Top Level.
You can always recover the error message and options available by typing ':error'
You can always type ':a' to exit the current break level and move to the next one up.
> (defun debug-me ( int num-times result )
(declare ( notinline debug-me ) )
(cond ((= num-times 0 ) result )
((= num-times 2 ) (break "Help this doesn't work" )
(debug-me int num-times ( + int result)))
( t (debug-me int (- num-times 1 ) (+ int result ) ) ) ) )
If you now invoke (debug-me 3 5 0 ) the function will run until
num-times is equal to 2 and then drop into the debugger. The message
that you pass to break is optional [ break takes an optional format string
and args for the format string if any ].
At this point you can enter ':c 1" to continue evaluation.
eval for example)got called the type ':b eval'.
You can look at the local variable bindings entering
CL-USER 23 : 1 > :n ; move up the stack from the break.
CL-USER 24 : 1 > :v
Interpreted call to DEBUG-ME :
INT : 3
NUM-TIMES : 2
RESULT : 9
Or at a particular local variable name:
CL-USER 25 : 1 > num-times
2
You could temporarly fix this by calling
CL-USER 26 : 1 > (setf num-times 1 ) ; but we're not suppose
;to use setf. :-)
and then typing
CL-USER 27 : 1 > :c 1
At which point the functions exits "normally". If you reinvoke that
function again and call up the stack backtrace you can examine
the previous invocations. You can go up to the top of the stack by typing
':p' and back down ( towards the initial caller ) by typing ':n'. If you are
looking at the stack backtrace just think of the emacs and 'p' to go to
previous ( up ) and 'n' to go to next (down).
(break) in your code can be a pain since your have to re-evaluate
the function to great the compiler to remove the "breakpoint". However,
this recompilation process is quite fast. Or you can try to use the
trace facility more effectively. See the trace minitutorial for more
info.