HELP BREAK John Williams, May 1987 Updated July 1995 CONTENTS - (Use g to access required sections) 1 Introduction 2 Summary of Debugger Commands 3 Examining the Call Stack 4 Examining Individual Stack Frames 5 Re-Displaying the Last Error Message 6 Exiting the Debugger 7 An Example 8 Interface between the Debugger and the Condition System 9 See Also ----------------------------------------------------------------------- 1 Introduction ----------------------------------------------------------------------- This file documents the Poplog Common Lisp Debugger. The Debugger may be entered in various ways: explicitly calling the function invoke-debugger on some condition; indirectly from the function break; after an error or warning; or following a keyboard interrupt. For further details of the situations in which an error or warning will lead to the Debugger being invoked, see HELP * MISHAP. The Lisp Debugger processes user input like a normal top-level loop, except that certain top-level forms (keywords) are interpreted as special debugger commands. Also, the prompt issued by the terminal read routine is changed. Here is the the output from a call to break: == (break) Break: (Simple-Condition) :h Help :c Return from break <0> The Debugger heralds its presence by printing "Break:" followed by the reason for its invocation (in parentheses). If it was entered due to an error, warning, or keyboard interrupt, then "(Error)", "(Warning)", or "(Interrupt)" will be printed. Otherwise (as in this example) the type of the condition on which the Debugger was invoked is printed. The next line is a reminder that typing :h causes a summary of the Debugger commmands to be displayed. Following the first two lines, a summary of the currently available restarts is printed (one per line). In this case, only one restart is available, which if invoked by typing :c, causes the call to break to return with the value nil. The sequence <0> is the read prompt, signifying that the Debugger is now ready to responmd to commands. The digit 0 indicates the level of the breakpoint. If the Debugger were to be invoked recursively, perhaps as a result of another error or keyboard interrupt, the prompt issued by the recursive call to the Debugger would be <1> (and so on). ----------------------------------------------------------------------- 2 Summary of Debugger Commands ----------------------------------------------------------------------- Commands that display information: :h Help, prints this :m Re-display last error message :dc Describe the condition on which the Debugger was entered :ic Inspect the condition on which the Debugger was entered :l List available restarts :b Display call stack backtrace :hide item Omit certain classes of functions from backtrace :unhide item Reverse effect of :hide Commands for selecting & inspecting individual stack frames: :b Display call stack backtrace :s frame Select frame :d frame Select and describe frame :i frame Select and inspect frame Commands for exiting the Debugger: :a Abort, reset Lisp system :q Quit to and resume previous break or top-level :! Fork a Unix shell (DCL on VMS platform) :c Invoke the restart named continue (if such exists) :c n Invoke the restart numbered n :r args Re-execute selected frame with args :v values Return values from selected frame Commands that invoke the Ved editor: :e Edit top level form currently being evaluated :ed frame Edit source code for frame ----------------------------------------------------------------------- 3 Examining the Call Stack ----------------------------------------------------------------------- To find out what functions were active when the break occurred, give the command: :b This is a typical display produced by :b *0: SEARCH 2: MEMBER 3: MYFUN 4: MYPROG The * indicates the currently selected stack frame (which can be altered by the :s, :d, and :i commands described below). If the output from :b threatens to overflow the screen, you will be asked whether more output should be displayed. Some frames may be omitted from the display (frame number 1 in the example above) - these belong either to functions defined in the system package, or Pop-11 procedures. The :hide and :unhide commands affect which frames are displayed: :hide package-name :unhide package-name These commands ensure that functions attached to internal symbols in the specified package-name will be invisible/visible in future backtraces. Supplying the package name pop11 causes Pop-11 procedures to be (un)hidden. It is also possible to omit specific functions from call stack backtraces, with the commands: :unhide :function frame :hide :function frame The argument frame may be either a stack frame number, or a function name. To disable all hiding, do: :unhide :all All stack frames will now be included in call stack backtraces. ----------------------------------------------------------------------- 4 Examining Individual Stack Frames ----------------------------------------------------------------------- To examine a particular stack frame, give one of the following commands: :s frame :d frame :i frame The desired frame may be specified by number, or by name (in which case the most recently constructed frame of that name is selected). The :s command simply selects the specified frame to be the current focus of attention. :d does likewise, but prints a description too (i.e. the name of the function, values of its local variables etc). The command :i is like :d but additionally invokes inspect on the selected frame, so that argument values may be examined and alterted. A sample stack frame display: Stackframe 1 Owner: {0} # Lexical variables: [1] A: C [2] B: (D E F) Important Note: Information about variable bindings is available only if the function was compiled with the declaration (optimize debug) in force. The source code for a user-defined function may be edited by giving the command: :ed frame ----------------------------------------------------------------------- 5 Re-Displaying the Last Error Message ----------------------------------------------------------------------- It may sometimes be useful to re-display the error message that caused the current break. The command :m is provided for this purpose. ----------------------------------------------------------------------- 6 Exiting the Debugger ----------------------------------------------------------------------- There are various ways to leave the Debugger: :a This calls setlisp, starting a brand new interactive top-level loop. (Note if Lisp is being run as a background job, the command :a will terminate the Lisp process). :q This unwinds to, and then resumes, the previous break or top-level loop. At top-level, is similar to :a. If the break occurred while compiling from a disk file, the compiler will move onto the next top-level form in the file. :c This invokes the nearest restart named continue, should one exist. The functions cerror, warn, and break all establish restarts named continue. The default keyboard interrupt handler (the value of the variable poplog:*interrupt*) does too. The next two commands enable control to be shifted to a frame other than the immediate caller of break: :r args This re-applies the function associated with the currently selected stack frame to a new set of arguments. args should be a single Lisp expression; hence to supply more than one argument, use values. For example: :r (values 'b '(a b c)) To return from the selected frame, passing control back to its caller, use: :v results Again, use values to specify multiple results. Important Note: For :r and :v to work correctly, the function being exited from must have been compiled with the declaration (optimize debug) in force. ----------------------------------------------------------------------- 7 An Example ----------------------------------------------------------------------- This example illustrates how a buggy discrimination net can be fixed using some of the debugging facilities described above. (defun discrim (tree) (declare (optimize debug)) (if (atom tree) tree (if (yes-or-no-p (first tree)) (discrim (second tree)) (discrim (third tree))))) (setq animals '("Can it fly" ("Does it have fea~hers" ("Is it black" blackbird thrush) ("Does it sting" bee butterfly)) ("Can it swim" ("Has it got fur" seal fish) ("Does it eat meat" cat rabbit)))) The function discrim is ok, but the net animals has a misplaced ~ in one of the questions. We try running discrim: (discrim animals) Can it fly (yes/no) yes ;;; MISHAP - Ill-formed directive parameter ;;; INVOLVING: "H" "Does it have fea~hers" ;;; FILE : /rsuna/home/johnw/cond/break ;;; LINE : 248 ;;; DOING : (DISCRIM ANIMALS) An error is signaled, then a break point is entered: Break: (Error) :H Help First, find out what function signaled the error, by examining a backtrace of the function call stack. Give the command :b <0> :b *0: ERROR 8: "~?" 15: FORMAT 17: YES-OR-NO-P 18: DISCRIM 19: DISCRIM format signaled the error, but it may be more profitable examining the call to discrim, with the command :i <0> :i 18 Stackframe 18 Owner: {0} # Lexical bindings: [1] TREE: ("Does it have fea~hers" ("Is it black" BLACKBIRD THRUSH) ("Does it sting" BEE BUTTERFLY)) The problem is discovered: the argument to discrim contains a string with a misplaced ~. Decide to fix it: inspect> 1 A list of length 3 [0] "Does it have fea~hers" [1] ("Is it black" BLACKBIRD THRUSH) [2] ("Does it sting" BEE BUTTERFLY) [3] End: NIL Replace the buggy string: inspect> s 0 "Does it have feathers" A list of length 3 [0] "Does it have feathers" [1] ("Is it black" BLACKBIRD THRUSH) [2] ("Does it sting" BEE BUTTERFLY) [3] End: NIL Save the modified argument to discrim in a temporary variable, foo: inspect> a foo Saved current object in FOO Quit the Inspector: inspect> q Restart the call to discrim, applying it to foo: <0> :r foo And now discrim works correctly: Does it have feathers (yes/no) no Does it sting (yes/no) no BUTTERFLY ----------------------------------------------------------------------- 8 Interface between the Debugger and the Condition System ----------------------------------------------------------------------- The condition object on which the Debugger has been invoked is kept in the variable poplog:*debugger-condition*. You can examine this condition with the command :dc which invokes describe on the condition, or with the command :ic which invokes inspect on the condition. To list the restarts associated with poplog:*debugger-condition*, give the command :l This prints a numbered list of all available restarts. To invoke a particular restart, give the command :c n where n is the number associated with the desired restart. ----------------------------------------------------------------------- 9 See Also ----------------------------------------------------------------------- HELP * DEBUG HELP * INSPECT HELP * MISHAP HELP * TRACE --- C.all/lisp/help/break --- Copyright University of Sussex 1989. All rights reserved.