1 /*
2 * NT exception handling routines
3 *
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdarg.h>
29
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winternl.h"
34 #include "wine/exception.h"
35 #include "wine/server.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
38 #include "excpt.h"
39 #include "ntdll_misc.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(seh);
42
43 typedef struct
44 {
45 struct list entry;
46 PVECTORED_EXCEPTION_HANDLER func;
47 ULONG count;
48 } VECTORED_HANDLER;
49
50 static struct list vectored_handlers = LIST_INIT(vectored_handlers);
51
52 static RTL_CRITICAL_SECTION vectored_handlers_section;
53 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
54 {
55 0, 0, &vectored_handlers_section,
56 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
57 0, 0, { (DWORD_PTR)(__FILE__ ": vectored_handlers_section") }
58 };
59 static RTL_CRITICAL_SECTION vectored_handlers_section = { &critsect_debug, -1, 0, 0, 0, 0 };
60
61 /**********************************************************************
62 * wait_suspend
63 *
64 * Wait until the thread is no longer suspended.
65 */
66 void wait_suspend( CONTEXT *context )
67 {
68 LARGE_INTEGER timeout;
69 int saved_errno = errno;
70 context_t server_context;
71
72 context_to_server( &server_context, context );
73
74 /* store the context we got at suspend time */
75 SERVER_START_REQ( set_suspend_context )
76 {
77 wine_server_add_data( req, &server_context, sizeof(server_context) );
78 wine_server_call( req );
79 }
80 SERVER_END_REQ;
81
82 /* wait with 0 timeout, will only return once the thread is no longer suspended */
83 timeout.QuadPart = 0;
84 NTDLL_wait_for_multiple_objects( 0, NULL, SELECT_INTERRUPTIBLE, &timeout, 0 );
85
86 /* retrieve the new context */
87 SERVER_START_REQ( get_suspend_context )
88 {
89 wine_server_set_reply( req, &server_context, sizeof(server_context) );
90 wine_server_call( req );
91 }
92 SERVER_END_REQ;
93
94 context_from_server( context, &server_context );
95 errno = saved_errno;
96 }
97
98
99 /**********************************************************************
100 * send_debug_event
101 *
102 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
103 */
104 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
105 {
106 NTSTATUS ret;
107 DWORD i;
108 HANDLE handle = 0;
109 client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
110 context_t server_context;
111
112 if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */
113
114 for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
115 params[i] = rec->ExceptionInformation[i];
116
117 context_to_server( &server_context, context );
118
119 SERVER_START_REQ( queue_exception_event )
120 {
121 req->first = first_chance;
122 req->code = rec->ExceptionCode;
123 req->flags = rec->ExceptionFlags;
124 req->record = wine_server_client_ptr( rec->ExceptionRecord );
125 req->address = wine_server_client_ptr( rec->ExceptionAddress );
126 req->len = i * sizeof(params[0]);
127 wine_server_add_data( req, params, req->len );
128 wine_server_add_data( req, &server_context, sizeof(server_context) );
129 if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
130 }
131 SERVER_END_REQ;
132 if (!handle) return 0;
133
134 NTDLL_wait_for_multiple_objects( 1, &handle, SELECT_INTERRUPTIBLE, NULL, 0 );
135
136 SERVER_START_REQ( get_exception_status )
137 {
138 req->handle = wine_server_obj_handle( handle );
139 wine_server_set_reply( req, &server_context, sizeof(server_context) );
140 ret = wine_server_call( req );
141 }
142 SERVER_END_REQ;
143 if (ret >= 0) context_from_server( context, &server_context );
144 return ret;
145 }
146
147
148 /**********************************************************************
149 * call_vectored_handlers
150 *
151 * Call the vectored handlers chain.
152 */
153 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
154 {
155 struct list *ptr;
156 LONG ret = EXCEPTION_CONTINUE_SEARCH;
157 EXCEPTION_POINTERS except_ptrs;
158 PVECTORED_EXCEPTION_HANDLER func;
159 VECTORED_HANDLER *handler, *to_free = NULL;
160
161 except_ptrs.ExceptionRecord = rec;
162 except_ptrs.ContextRecord = context;
163
164 RtlEnterCriticalSection( &vectored_handlers_section );
165 ptr = list_head( &vectored_handlers );
166 while (ptr)
167 {
168 handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
169 handler->count++;
170 func = RtlDecodePointer( handler->func );
171 RtlLeaveCriticalSection( &vectored_handlers_section );
172 RtlFreeHeap( GetProcessHeap(), 0, to_free );
173 to_free = NULL;
174
175 TRACE( "calling handler at %p code=%x flags=%x\n",
176 func, rec->ExceptionCode, rec->ExceptionFlags );
177 ret = func( &except_ptrs );
178 TRACE( "handler at %p returned %x\n", func, ret );
179
180 RtlEnterCriticalSection( &vectored_handlers_section );
181 ptr = list_next( &vectored_handlers, ptr );
182 if (!--handler->count) /* removed during execution */
183 {
184 list_remove( &handler->entry );
185 to_free = handler;
186 }
187 if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
188 }
189 RtlLeaveCriticalSection( &vectored_handlers_section );
190 RtlFreeHeap( GetProcessHeap(), 0, to_free );
191 return ret;
192 }
193
194
195 /*******************************************************************
196 * raise_status
197 *
198 * Implementation of RtlRaiseStatus with a specific exception record.
199 */
200 void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
201 {
202 EXCEPTION_RECORD ExceptionRec;
203
204 ExceptionRec.ExceptionCode = status;
205 ExceptionRec.ExceptionFlags = EH_NONCONTINUABLE;
206 ExceptionRec.ExceptionRecord = rec;
207 ExceptionRec.NumberParameters = 0;
208 for (;;) RtlRaiseException( &ExceptionRec ); /* never returns */
209 }
210
211
212 /***********************************************************************
213 * RtlRaiseStatus (NTDLL.@)
214 *
215 * Raise an exception with ExceptionCode = status
216 */
217 void WINAPI RtlRaiseStatus( NTSTATUS status )
218 {
219 raise_status( status, NULL );
220 }
221
222
223 /*******************************************************************
224 * RtlAddVectoredExceptionHandler (NTDLL.@)
225 */
226 PVOID WINAPI RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
227 {
228 VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
229 if (handler)
230 {
231 handler->func = RtlEncodePointer( func );
232 handler->count = 1;
233 RtlEnterCriticalSection( &vectored_handlers_section );
234 if (first) list_add_head( &vectored_handlers, &handler->entry );
235 else list_add_tail( &vectored_handlers, &handler->entry );
236 RtlLeaveCriticalSection( &vectored_handlers_section );
237 }
238 return handler;
239 }
240
241
242 /*******************************************************************
243 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
244 */
245 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
246 {
247 struct list *ptr;
248 ULONG ret = FALSE;
249
250 RtlEnterCriticalSection( &vectored_handlers_section );
251 LIST_FOR_EACH( ptr, &vectored_handlers )
252 {
253 VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
254 if (curr_handler == handler)
255 {
256 if (!--curr_handler->count) list_remove( ptr );
257 else handler = NULL; /* don't free it yet */
258 ret = TRUE;
259 break;
260 }
261 }
262 RtlLeaveCriticalSection( &vectored_handlers_section );
263 if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
264 return ret;
265 }
266
267
268 /*************************************************************
269 * __wine_spec_unimplemented_stub
270 *
271 * ntdll-specific implementation to avoid depending on kernel functions.
272 * Can be removed once ntdll.spec no longer contains stubs.
273 */
274 void __wine_spec_unimplemented_stub( const char *module, const char *function )
275 {
276 EXCEPTION_RECORD record;
277
278 record.ExceptionCode = EXCEPTION_WINE_STUB;
279 record.ExceptionFlags = EH_NONCONTINUABLE;
280 record.ExceptionRecord = NULL;
281 record.ExceptionAddress = __wine_spec_unimplemented_stub;
282 record.NumberParameters = 2;
283 record.ExceptionInformation[0] = (ULONG_PTR)module;
284 record.ExceptionInformation[1] = (ULONG_PTR)function;
285 for (;;) RtlRaiseException( &record );
286 }
287
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.