1 ;;;; miscellaneous error stuff that needs to be in the cold load
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!KERNEL")
14 (defvar *break-on-signals* nil
16 "When (TYPEP condition *BREAK-ON-SIGNALS*) is true, then calls to SIGNAL will
17 enter the debugger prior to signalling that condition.")
19 (defun signal (datum &rest arguments)
21 "Invokes the signal facility on a condition formed from DATUM and
22 ARGUMENTS. If the condition is not handled, NIL is returned. If
23 (TYPEP condition *BREAK-ON-SIGNALS*) is true, the debugger is invoked
24 before any signalling is done."
25 (/noshow0 "entering SIGNAL")
26 (let ((condition (coerce-to-condition datum
30 (*handler-clusters* *handler-clusters*))
31 (let ((old-bos *break-on-signals*)
32 (*break-on-signals* nil))
33 (when (typep condition old-bos)
34 (/noshow0 "doing BREAK in because of *BREAK-ON-SIGNALS*")
35 (break "~A~%BREAK was entered because of *BREAK-ON-SIGNALS* (now rebound to NIL)."
38 (unless *handler-clusters*
39 (/noshow0 "leaving LOOP because of unbound *HANDLER-CLUSTERS*")
41 (let ((cluster (pop *handler-clusters*)))
42 (/noshow0 "got CLUSTER=..")
44 (dolist (handler cluster)
45 (/noshow0 "looking at HANDLER=..")
47 (when (typep condition (car handler))
48 (funcall (cdr handler) condition)))))
50 (/noshow0 "returning from SIGNAL")
53 ;;; a utility for SIGNAL, ERROR, CERROR, WARN, and INVOKE-DEBUGGER:
54 ;;; Parse the hairy argument conventions into a single argument that's
55 ;;; directly usable by all the other routines.
56 (defun coerce-to-condition (datum arguments default-type fun-name)
57 (cond ((typep datum 'condition)
59 (cerror "Ignore the additional arguments."
63 :format-control "You may not supply additional arguments ~
64 when giving ~S to ~S."
65 :format-arguments (list datum fun-name)))
67 ((symbolp datum) ; roughly, (SUBTYPEP DATUM 'CONDITION)
68 (apply #'make-condition datum arguments))
69 ((or (stringp datum) (functionp datum))
70 (make-condition default-type
72 :format-arguments arguments))
74 (error 'simple-type-error
76 :expected-type '(or symbol string)
77 :format-control "bad argument to ~S: ~S"
78 :format-arguments (list fun-name datum)))))
80 ;;; a shared idiom in ERROR, CERROR, and BREAK: The user probably
81 ;;; doesn't want to hear that the error "occurred in" one of these
82 ;;; functions, so we try to point the top of the stack to our caller
84 (eval-when (:compile-toplevel :execute)
85 (defmacro-mundanely maybe-find-stack-top-hint ()
86 `(or sb!debug:*stack-top-hint*
87 (nth-value 1 (find-caller-name-and-frame)))))
89 (defun error (datum &rest arguments)
91 "Invoke the signal facility on a condition formed from DATUM and ARGUMENTS.
92 If the condition is not handled, the debugger is invoked."
93 (/show0 "entering ERROR, argument list=..")
96 (/show0 "cold-printing ERROR arguments one by one..")
97 #!+sb-show (dolist (argument arguments)
98 (sb!impl::cold-print argument))
99 (/show0 "done cold-printing ERROR arguments")
101 (infinite-error-protect
102 (let ((condition (coerce-to-condition datum arguments
103 'simple-error 'error))
104 (sb!debug:*stack-top-hint* (maybe-find-stack-top-hint)))
105 (/show0 "done coercing DATUM to CONDITION")
106 (let ((sb!debug:*stack-top-hint* nil))
107 (/show0 "signalling CONDITION from within ERROR")
109 (/show0 "done signalling CONDITION within ERROR")
110 (invoke-debugger condition))))
112 (defun cerror (continue-string datum &rest arguments)
113 (infinite-error-protect
115 (continue "~A" (apply #'format nil continue-string arguments))
116 (let ((condition (coerce-to-condition datum
120 (sb!debug:*stack-top-hint* (maybe-find-stack-top-hint)))
121 (with-condition-restarts condition (list (find-restart 'continue))
122 (let ((sb!debug:*stack-top-hint* nil))
124 (invoke-debugger condition)))))
127 ;;; like BREAK, but without rebinding *DEBUGGER-HOOK* to NIL, so that
128 ;;; we can use it in system code (e.g. in SIGINT handling) without
129 ;;; messing up --disable-debugger mode (which works by setting
130 ;;; *DEBUGGER-HOOK*); or for that matter, without messing up ordinary
131 ;;; applications which try to do similar things with *DEBUGGER-HOOK*
132 (defun %break (what &optional (datum "break") &rest arguments)
133 (infinite-error-protect
134 (with-simple-restart (continue "Return from ~S." what)
135 (let ((sb!debug:*stack-top-hint* (maybe-find-stack-top-hint)))
137 (coerce-to-condition datum arguments 'simple-condition what)))))
140 (defun break (&optional (datum "break") &rest arguments)
142 "Print a message and invoke the debugger without allowing any possibility
143 of condition handling occurring."
144 (let ((*debugger-hook* nil)) ; as specifically required by ANSI
145 (apply #'%break 'break datum arguments)))
147 (defun warn (datum &rest arguments)
149 "Warn about a situation by signalling a condition formed by DATUM and
150 ARGUMENTS. While the condition is being signaled, a MUFFLE-WARNING restart
151 exists that causes WARN to immediately return NIL."
152 (/show0 "entering WARN")
153 ;; KLUDGE: The current cold load initialization logic causes several calls
154 ;; to WARN, so we need to be able to handle them without dying. (And calling
155 ;; FORMAT or even PRINC in cold load is a good way to die.) Of course, the
156 ;; ideal would be to clean up cold load so that it doesn't call WARN..
158 (if (not *cold-init-complete-p*)
160 (/show0 "ignoring WARN in cold init, arguments=..")
161 #!+sb-show (dolist (argument arguments)
162 (sb!impl::cold-print argument)))
163 (infinite-error-protect
164 (/show0 "doing COERCE-TO-CONDITION")
165 (let ((condition (coerce-to-condition datum arguments
166 'simple-warning 'warn)))
167 (/show0 "back from COERCE-TO-CONDITION, doing ENFORCE-TYPE")
168 (enforce-type condition warning)
169 (/show0 "back from ENFORCE-TYPE, doing RESTART-CASE MUFFLE-WARNING")
170 (restart-case (signal condition)
172 :report "Skip warning."
173 (return-from warn nil)))
174 (/show0 "back from RESTART-CASE MUFFLE-WARNING (i.e. normal return)")
176 (let ((badness (etypecase condition
177 (style-warning 'style-warning)
178 (warning 'warning))))
179 (/show0 "got BADNESS, calling FORMAT")
180 (format *error-output*
181 "~&~@<~S: ~3i~:_~A~:>~%"
184 (/show0 "back from FORMAT, voila!")))))