1 ;;;; code for handling Win32 exceptions
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!WIN32")
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.
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.
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).
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).
35 ;;; This specific bit of functionality may well be implemented entirely
38 (defun sigint-%break
(format-string &rest format-arguments
)
40 (apply #'%break
'sigint format-string format-arguments
)))
41 (sb!thread
:interrupt-thread
(sb!thread
::foreground-thread
) #'break-it
)))
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
))))))
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
)
58 (cons +exception-stack-overflow
+ 'sb
!kernel
::control-stack-exhausted
)
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
+))))
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"
92 (sap-alien (deref (slot record
'exception-information
) 1)
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
)))))
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")
125 (defun receive-pending-interrupt ()
126 (receive-pending-interrupt))
128 (defmacro with-interrupt-bindings
(&body body
)
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
136 ((sb!pcl
::*cache-miss-values-stack
* nil
)
137 (sb!pcl
::*dfun-miss-gfs-on-stack
* nil
))
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
))
147 (allow-with-interrupts
151 ,@cleanup-froms
))))))
153 (declaim (inline %unblock-deferrable-signals
))
154 (define-alien-routine ("unblock_deferrable_signals"
155 %unblock-deferrable-signals
)
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
)
170 (define-alien-routine ("apply_sigmask"
175 ;; KLUDGE: unused, was intended for invoke-interruption below?
176 (defmacro without-interrupts
/with-deferrables-blocked
(&body body
)
177 (let ((mask-var (gensym)))
179 (let ((,mask-var
(%block-deferrables-and-return-mask
)))
182 (%apply-sigmask
,mask-var
))))))
184 (defun invoke-interruption (function)
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
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
)
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
()
218 "Enable all the default signals that Lisp knows how to deal with."
219 (unblock-deferrable-signals)