X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcode%2Fdebug.lisp;h=7ac94694a4122fbd3bc05fdbf682c796b3ed676b;hb=41ed816c7915806abca6b09ecd2136458f27adcc;hp=b969a583018193fc2614656d1d3923de4355e841;hpb=816248ab4fe04775879a7e5a5ce1b4c613afe9d5;p=sbcl.git diff --git a/src/code/debug.lisp b/src/code/debug.lisp index b969a58..7ac9469 100644 --- a/src/code/debug.lisp +++ b/src/code/debug.lisp @@ -13,11 +13,28 @@ ;;;; variables and constants -(defvar *debug-print-level* 3 +;;; things to consider when tweaking these values: +;;; * We're afraid to just default them to NIL and NIL, in case the +;;; user inadvertently causes a hairy data structure to be printed +;;; when he inadvertently enters the debugger. +;;; * We don't want to truncate output too much. These days anyone +;;; can easily run their Lisp in a windowing system or under Emacs, +;;; so it's not the end of the world even if the worst case is a +;;; few thousand lines of output. +;;; * As condition :REPORT methods are converted to use the pretty +;;; printer, they acquire *PRINT-LEVEL* constraints, so e.g. under +;;; sbcl-0.7.1.28's old value of *DEBUG-PRINT-LEVEL*=3, an +;;; ARG-COUNT-ERROR printed as +;;; error while parsing arguments to DESTRUCTURING-BIND: +;;; invalid number of elements in +;;; # +;;; to satisfy lambda list +;;; #: +;;; exactly 2 expected, but 5 found +(defvar *debug-print-level* 5 #!+sb-doc "*PRINT-LEVEL* for the debugger") - -(defvar *debug-print-length* 5 +(defvar *debug-print-length* 7 #!+sb-doc "*PRINT-LENGTH* for the debugger") @@ -61,22 +78,24 @@ *debug-command-level*)) (defparameter *debug-help-string* -"The prompt is right square brackets, the number indicating how many - recursive command loops you are in. -Any command may be uniquely abbreviated. +"The prompt is square brackets, with number(s) indicating the current control + stack level and, if you've entered the debugger recursively, how deeply + recursed you are. +Any command -- including the name of a restart -- may be uniquely abbreviated. The debugger rebinds various special variables for controlling i/o, sometimes to defaults (much like WITH-STANDARD-IO-SYNTAX does) and sometimes to its own special values, e.g. SB-DEBUG:*DEBUG-PRINT-LEVEL*. -Debug commands do not affect * and friends, but evaluation in the debug loop - does affect these variables. +Debug commands do not affect *, //, and similar variables, but evaluation in + the debug loop does affect these variables. SB-DEBUG:*FLUSH-DEBUG-ERRORS* controls whether errors at the debug prompt - drop you into deeper into the debugger. + drop you deeper into the debugger. Getting in and out of the debugger: RESTART invokes restart numbered as shown (prompt if not given). ERROR prints the error condition and restart cases. - The name of any restart, or its number, is a valid command, and is the same - as using RESTART to invoke that restart. + The number of any restart, or its name, or a unique abbreviation for its + name, is a valid command, and is the same as using RESTART to invoke that + restart. Changing frames: U up frame D down frame @@ -108,7 +127,12 @@ Function and macro commands: (SB-DEBUG:ARG n) Return the n'th argument in the current frame. (SB-DEBUG:VAR string-or-symbol [id]) - Returns the value of the specified variable in the current frame.") + Returns the value of the specified variable in the current frame. + +Other commands: + SLURP Discard all pending input on *STANDARD-INPUT*. (This can be + useful when the debugger was invoked to handle an error in + deeply nested input syntax, and now the reader is confused.)") ;;; This is used to communicate to DEBUG-LOOP that we are at a step breakpoint. (define-condition step-condition (simple-condition) ()) @@ -244,30 +268,32 @@ Function and macro commands: ;;;; the BREAKPOINT-INFO structure ;;; info about a made breakpoint -(defstruct (breakpoint-info (:copier nil)) +(defstruct (breakpoint-info (:copier nil) + (:constructor %make-breakpoint-info)) ;; where we are going to stop - (place (missing-arg) :type (or sb!di:code-location sb!di:debug-fun)) - ;; the breakpoint returned by sb!di:make-breakpoint - (breakpoint (missing-arg) :type sb!di:breakpoint) + (place (missing-arg) + :type (or sb!di:code-location sb!di:debug-fun) + :read-only t) + ;; the breakpoint returned by SB!DI:MAKE-BREAKPOINT + (breakpoint (missing-arg) :type sb!di:breakpoint :read-only t) ;; the function returned from SB!DI:PREPROCESS-FOR-EVAL. If result is ;; non-NIL, drop into the debugger. - (break #'identity :type function) - ;; the function returned from sb!di:preprocess-for-eval. If result is + (break #'identity :type function :read-only t) + ;; the function returned from SB!DI:PREPROCESS-FOR-EVAL. If result is ;; non-NIL, eval (each) print and print results. - (condition #'identity :type function) - ;; the list of functions from sb!di:preprocess-for-eval to evaluate. - ;; Results are conditionally printed. Car of each element is the - ;; function, cdr is the form it goes with. - (print nil :type list) + (condition #'identity :type function :read-only t) + ;; the list of functions from SB!DI:PREPROCESS-FOR-EVAL to evaluate. + ;; Results are conditionally printed. CAR of each element is the + ;; function, CDR is the form it goes with. + (print nil :type list :read-only t) ;; the number used when listing the possible breakpoints within a - ;; function. Could also be a symbol such as start or end. - (code-location-number (missing-arg) :type (or symbol integer)) - ;; the number used when listing the breakpoints active and to delete - ;; breakpoints - (breakpoint-number (missing-arg) :type integer)) - -;;; Return a new BREAKPOINT-INFO structure with the info passed. -(defun create-breakpoint-info (place breakpoint code-location-number + ;; function; or could also be a symbol such as START or END + (code-location-selector (missing-arg) :type (or symbol integer) :read-only t) + ;; the number used when listing the active breakpoints, and when + ;; deleting breakpoints + (breakpoint-number (missing-arg) :type integer) :read-only t) + +(defun create-breakpoint-info (place breakpoint code-location-selector &key (break #'identity) (condition #'identity) (print nil)) (setf *breakpoints* @@ -279,25 +305,25 @@ Function and macro commands: (first breakpoints))))) i)))) - (make-breakpoint-info :place place :breakpoint breakpoint - :code-location-number code-location-number - :breakpoint-number breakpoint-number - :break break :condition condition :print print))) + (%make-breakpoint-info :place place + :breakpoint breakpoint + :code-location-selector code-location-selector + :breakpoint-number breakpoint-number + :break break + :condition condition + :print print))) -;;; Print the breakpoint info for the breakpoint-info structure passed. (defun print-breakpoint-info (breakpoint-info) (let ((place (breakpoint-info-place breakpoint-info)) - (bp-number (breakpoint-info-breakpoint-number breakpoint-info)) - (loc-number (breakpoint-info-code-location-number breakpoint-info))) + (bp-number (breakpoint-info-breakpoint-number breakpoint-info))) (case (sb!di:breakpoint-kind (breakpoint-info-breakpoint breakpoint-info)) (:code-location (print-code-location-source-form place 0) (format t "~&~S: ~S in ~S" bp-number - loc-number - (sb!di:debug-fun-name (sb!di:code-location-debug-fun - place)))) + (breakpoint-info-code-location-selector breakpoint-info) + (sb!di:debug-fun-name (sb!di:code-location-debug-fun place)))) (:fun-start (format t "~&~S: FUN-START in ~S" bp-number (sb!di:debug-fun-name place))) @@ -475,12 +501,11 @@ Function and macro commands: ) ; EVAL-WHEN ;;; This is used in constructing arg lists for debugger printing when -;;; the arg list is unavailable, some arg is unavailable or unused, -;;; etc. +;;; the arg list is unavailable, some arg is unavailable or unused, etc. (defstruct (unprintable-object (:constructor make-unprintable-object (string)) (:print-object (lambda (x s) - (print-unreadable-object (x s :type t) + (print-unreadable-object (x s) (write-string (unprintable-object-string x) s)))) (:copier nil)) @@ -591,6 +616,7 @@ Function and macro commands: ;;; These are bound on each invocation of INVOKE-DEBUGGER. (defvar *debug-restarts*) (defvar *debug-condition*) +(defvar *nested-debug-condition*) (defun invoke-debugger (condition) #!+sb-doc @@ -599,7 +625,9 @@ Function and macro commands: (when old-hook (let ((*debugger-hook* nil)) (funcall old-hook condition old-hook)))) - (sb!unix:unix-sigsetmask 0) + ;; FIXME: No-one seems to know what this is for. Nothing is noticeably + ;; broken on sunos... + #!-sunos (sb!unix:unix-sigsetmask 0) ;; Elsewhere in the system, we use the SANE-PACKAGE function for ;; this, but here causing an exception just as we're trying to handle @@ -635,7 +663,8 @@ reset to ~S." (*readtable* *debug-readtable*) (*print-readably* nil) (*print-pretty* t) - (*package* original-package)) + (*package* original-package) + (*nested-debug-condition* nil)) ;; Before we start our own output, finish any pending output. ;; Otherwise, if the user tried to track the progress of @@ -655,14 +684,21 @@ reset to ~S." (type-of *debug-condition*) *debug-condition*) (error (condition) - (format *error-output* - "~&(caught ~S trying to print ~S when entering debugger)~%" - (type-of condition) - '*debug-condition*) + (setf *nested-debug-condition* condition) + (let ((ndc-type (type-of *nested-debug-condition*))) + (format *error-output* + "~&~@<(A ~S was caught when trying to print ~S when ~ + entering the debugger. Printing was aborted and the ~ + ~S was stored in ~S.)~@:>~%" + ndc-type + '*debug-condition* + ndc-type + '*nested-debug-condition*)) (when (typep condition 'cell-error) ;; what we really want to know when it's e.g. an UNBOUND-VARIABLE: (format *error-output* - "~&(CELL-ERROR-NAME = ~S)~%)" + "~&(CELL-ERROR-NAME ~S) = ~S~%" + '*debug-condition* (cell-error-name *debug-condition*))))) ;; After the initial error/condition/whatever announcement to @@ -672,15 +708,14 @@ reset to ~S." ;; older debugger code which was written to do i/o on whatever ;; stream was in fashion at the time, and not all of it has ;; been converted to behave this way. -- WHN 2000-11-16) - (let (;; FIXME: The first two bindings here seem wrong, + (let (;; FIXME: Rebinding *STANDARD-OUTPUT* here seems wrong, ;; violating the principle of least surprise, and making ;; it impossible for the user to do reasonable things ;; like using PRINT at the debugger prompt to send output ;; to the program's ordinary (possibly - ;; redirected-to-a-file) *STANDARD-OUTPUT*, or using - ;; PEEK-CHAR or some such thing on the program's ordinary - ;; (possibly also redirected) *STANDARD-INPUT*. - (*standard-input* *debug-io*) + ;; redirected-to-a-file) *STANDARD-OUTPUT*. (CMU CL + ;; used to rebind *STANDARD-INPUT* here too, but that's + ;; been fixed already.) (*standard-output* *debug-io*) ;; This seems reasonable: e.g. if the user has redirected ;; *ERROR-OUTPUT* to some log file, it's probably wrong @@ -779,7 +814,7 @@ reset to ~S." '*flush-debug-errors*) (/show0 "throwing DEBUG-LOOP-CATCHER") (throw 'debug-loop-catcher nil))))) - ;; We have to bind level for the restart function created by + ;; We have to bind LEVEL for the restart function created by ;; WITH-SIMPLE-RESTART. (let ((level *debug-command-level*) (restart-commands (make-restart-commands))) @@ -802,7 +837,7 @@ reset to ~S." (apply cmd-fun (sb!int:stream-command-args input)))))) (t - (let* ((exp (read)) + (let* ((exp (read *debug-io*)) (cmd-fun (debug-command-p exp restart-commands))) (cond ((not cmd-fun) @@ -1179,7 +1214,7 @@ argument") (show-restarts *debug-restarts* *debug-io*) (write-string "restart: ") (force-output) - (setf num (read *standard-input*))) + (setf num (read *debug-io*))) (let ((restart (typecase num (unsigned-byte (nth num *debug-restarts*)) @@ -1594,17 +1629,19 @@ argument") (if function (describe function) (format t "can't figure out the function for this frame")))) + +(!def-debug-command "SLURP" () + (loop while (read-char-no-hang *standard-input*))) ;;;; debug loop command utilities -(defun read-prompting-maybe (prompt &optional (in *standard-input*) - (out *standard-output*)) - (unless (sb!int:listen-skip-whitespace in) - (princ prompt out) - (force-output out)) - (read in)) +(defun read-prompting-maybe (prompt) + (unless (sb!int:listen-skip-whitespace *debug-io*) + (princ prompt) + (force-output)) + (read *debug-io*)) -(defun read-if-available (default &optional (stream *standard-input*)) - (if (sb!int:listen-skip-whitespace stream) - (read stream) +(defun read-if-available (default) + (if (sb!int:listen-skip-whitespace *debug-io*) + (read *debug-io*) default))