Fix grammar in lossage message
[sbcl.git] / src / code / target-exception.lisp
blob45dddd1704863362bc2b8b33fffe239607dd9bb4
1 ;;;; code for handling Win32 exceptions
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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!WIN32")
14 ;;;
15 ;;; An awful lot of this stuff is stubbed out for now. We basically
16 ;;; only handle inbound exceptions (the local equivalent to unblockable
17 ;;; signals), and we're only picking off the sigsegv and sigfpe traps.
18 ;;;
19 ;;; This file is based on target-signal.lisp, but most of that went
20 ;;; away. Some of it might want to be put back or emulated.
21 ;;;
23 ;;; SIGINT is handled like BREAK, except that ANSI BREAK ignores
24 ;;; *DEBUGGER-HOOK*, but we want SIGINT's BREAK to respect it, so that
25 ;;; SIGINT in --disable-debugger mode will cleanly terminate the system
26 ;;; (by respecting the *DEBUGGER-HOOK* established in that mode).
27 ;;;
28 ;;; We'd like to have this work, but that would require some method of
29 ;;; delivering a "blockable signal". Windows doesn't really have the
30 ;;; concept, so we need to play with the threading functions to emulate
31 ;;; it (especially since the local equivalent of SIGINT comes in on a
32 ;;; separate thread). This is on the list for fixing later on, and will
33 ;;; be required before we implement threads (because of stop-for-gc).
34 ;;;
35 ;;; This specific bit of functionality may well be implemented entirely
36 ;;; in the runtime.
37 #||
38 (defun sigint-%break (format-string &rest format-arguments)
39 (flet ((break-it ()
40 (apply #'%break 'sigint format-string format-arguments)))
41 (sb!thread:interrupt-thread (sb!thread::foreground-thread) #'break-it)))
42 ||#
44 ;;; Map Windows Exception code to condition names: symbols or strings
45 (defvar *exception-code-map*
46 (macrolet ((cons-name (symbol)
47 `(cons ,symbol ,(remove #\+ (substitute #\_ #\- (string symbol))))))
48 (list
49 ;; Floating point exceptions
50 (cons +exception-flt-divide-by-zero+ 'division-by-zero)
51 (cons +exception-flt-invalid-operation+ 'floating-point-invalid-operation)
52 (cons +exception-flt-underflow+ 'floating-point-underflow)
53 (cons +exception-flt-overflow+ 'floating-point-overflow)
54 (cons +exception-flt-inexact-result+ 'floating-point-inexact)
55 (cons +exception-flt-denormal-operand+ 'floating-point-exception)
56 (cons +exception-flt-stack-check+ 'floating-point-exception)
57 ;; Stack overflow
58 (cons +exception-stack-overflow+ 'sb!kernel::control-stack-exhausted)
59 ;; Various
60 (cons-name +exception-single-step+)
61 (cons-name +exception-access-violation+) ; FIXME: should turn into MEMORY-FAULT-ERROR
62 ; plus the faulting address
63 (cons-name +exception-array-bounds-exceeded+)
64 (cons-name +exception-breakpoint+)
65 (cons-name +exception-datatype-misalignment+)
66 (cons-name +exception-illegal-instruction+)
67 (cons-name +exception-in-page-error+)
68 (cons-name +exception-int-divide-by-zero+)
69 (cons-name +exception-int-overflow+)
70 (cons-name +exception-invalid-disposition+)
71 (cons-name +exception-noncontinuable-exception+)
72 (cons-name +exception-priv-instruction+))))
74 (define-alien-type ()
75 (struct exception-record
76 (exception-code dword)
77 (exception-flags dword)
78 (exception-record system-area-pointer)
79 (exception-address system-area-pointer)
80 (number-parameters dword)
81 (exception-information (array system-area-pointer
82 #.+exception-maximum-parameters+))))
84 ;;; DBG_PRINTEXCEPTION_C shouldn'tbe fatal, and even if it is related to
85 ;;; something bad, better to print the message than just fail with no info
86 (defun dbg-printexception-c (record)
87 (when (= (slot record 'number-parameters) 2)
88 ;; (sap-int (deref (slot record 'exception-information) 0)) =
89 ;; length of string including 0-terminator
90 (warn "DBG_PRINTEXCEPTION_C: ~a"
91 (cast
92 (sap-alien (deref (slot record 'exception-information) 1)
93 (* char))
94 c-string))))
96 ;;; Actual exception handler. We hit something the runtime doesn't
97 ;;; want to or know how to deal with (that is, not a sigtrap or gc wp
98 ;;; violation), so it calls us here.
99 (defun sb!kernel:handle-win32-exception (context-sap exception-record-sap)
100 (let* ((record (deref (sap-alien exception-record-sap (* (struct exception-record)))))
101 (code (slot record 'exception-code))
102 (condition-name (cdr (assoc code *exception-code-map*)))
103 (sb!debug:*stack-top-hint* (sb!kernel:find-interrupted-frame)))
104 (cond (condition-name
105 (error condition-name))
106 ((= code +dbg-printexception-c+)
107 (dbg-printexception-c record))
109 (error "An exception occurred in context ~S: ~S. (Exception code: ~S)"
110 context-sap exception-record-sap code)))))
112 ;;;; etc.
114 ;;; CMU CL comment:
115 ;;; Magically converted by the compiler into a break instruction.
116 ;;; SBCL/Win32 comment:
117 ;;; I don't know if we still need this or not. Better safe for now.
118 (defun receive-pending-interrupt ()
119 (receive-pending-interrupt))
121 (in-package "SB!UNIX")
123 #!+sb-thread
124 (progn
125 (defun receive-pending-interrupt ()
126 (receive-pending-interrupt))
128 (defmacro with-interrupt-bindings (&body body)
129 `(let*
130 ;; KLUDGE: Whatever is on the PCL stacks before the interrupt
131 ;; handler runs doesn't really matter, since we're not on the
132 ;; same call stack, really -- and if we don't bind these (esp.
133 ;; the cache one) we can get a bogus metacircle if an interrupt
134 ;; handler calls a GF that was being computed when the interrupt
135 ;; hit.
136 ((sb!pcl::*cache-miss-values-stack* nil)
137 (sb!pcl::*dfun-miss-gfs-on-stack* nil))
138 ,@body))
140 ;;; Evaluate CLEANUP-FORMS iff PROTECTED-FORM does a non-local exit.
141 (defmacro nlx-protect (protected-form &rest cleanup-froms)
142 (with-unique-names (completep)
143 `(let ((,completep nil))
144 (without-interrupts
145 (unwind-protect
146 (progn
147 (allow-with-interrupts
148 ,protected-form)
149 (setq ,completep t))
150 (unless ,completep
151 ,@cleanup-froms))))))
153 (declaim (inline %unblock-deferrable-signals))
154 (define-alien-routine ("unblock_deferrable_signals"
155 %unblock-deferrable-signals)
156 void
157 (where unsigned)
158 (old unsigned))
160 (defun block-deferrable-signals ()
161 (%block-deferrable-signals 0 0))
163 (defun unblock-deferrable-signals ()
164 (%unblock-deferrable-signals 0 0))
166 (declaim (inline %block-deferrables-and-return-mask %apply-sigmask))
167 (define-alien-routine ("block_deferrables_and_return_mask"
168 %block-deferrables-and-return-mask)
169 unsigned)
170 (define-alien-routine ("apply_sigmask"
171 %apply-sigmask)
172 void
173 (mask unsigned))
175 ;; KLUDGE: unused, was intended for invoke-interruption below?
176 (defmacro without-interrupts/with-deferrables-blocked (&body body)
177 (let ((mask-var (gensym)))
178 `(without-interrupts
179 (let ((,mask-var (%block-deferrables-and-return-mask)))
180 (unwind-protect
181 (progn ,@body)
182 (%apply-sigmask ,mask-var))))))
184 (defun invoke-interruption (function)
185 (without-interrupts
186 ;; Reset signal mask: the C-side handler has blocked all
187 ;; deferrable signals before funcalling into lisp. They are to be
188 ;; unblocked the first time interrupts are enabled. With this
189 ;; mechanism there are no extra frames on the stack from a
190 ;; previous signal handler when the next signal is delivered
191 ;; provided there is no WITH-INTERRUPTS.
192 (let ((*unblock-deferrables-on-enabling-interrupts-p* t))
193 (with-interrupt-bindings
194 (let ((sb!debug:*stack-top-hint*
195 (sb!kernel:find-interrupted-frame)))
196 (allow-with-interrupts
197 (nlx-protect
198 (funcall function)
199 ;; We've been running with deferrables
200 ;; blocked in Lisp called by a C signal
201 ;; handler. If we return normally the sigmask
202 ;; in the interrupted context is restored.
203 ;; However, if we do an nlx the operating
204 ;; system will not restore it for us.
205 (when *unblock-deferrables-on-enabling-interrupts-p*
206 ;; This means that storms of interrupts
207 ;; doing an nlx can still run out of stack.
208 (unblock-deferrable-signals)))))))))
210 (defmacro in-interruption ((&key) &body body)
211 #!+sb-doc
212 "Convenience macro on top of INVOKE-INTERRUPTION."
213 `(dx-flet ((interruption () ,@body))
214 (invoke-interruption #'interruption)))
216 (defun sb!kernel:signal-cold-init-or-reinit ()
217 #!+sb-doc
218 "Enable all the default signals that Lisp knows how to deal with."
219 (unblock-deferrable-signals)
220 (values)))