usp10/tests: A spelling fix in an ok() message.
[wine.git] / dlls / ntdll / exception.c
blob3792b69aed932b8c9c1bdf216241f9ff7f3330ce
1 /*
2 * NT exception handling routines
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdarg.h>
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"
41 WINE_DEFAULT_DEBUG_CHANNEL(seh);
43 typedef struct
45 struct list entry;
46 PVECTORED_EXCEPTION_HANDLER func;
47 ULONG count;
48 } VECTORED_HANDLER;
50 static struct list vectored_exception_handlers = LIST_INIT(vectored_exception_handlers);
51 static struct list vectored_continue_handlers = LIST_INIT(vectored_continue_handlers);
53 static RTL_CRITICAL_SECTION vectored_handlers_section;
54 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
56 0, 0, &vectored_handlers_section,
57 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
58 0, 0, { (DWORD_PTR)(__FILE__ ": vectored_handlers_section") }
60 static RTL_CRITICAL_SECTION vectored_handlers_section = { &critsect_debug, -1, 0, 0, 0, 0 };
62 static PRTL_EXCEPTION_FILTER unhandled_exception_filter;
65 static VECTORED_HANDLER *add_vectored_handler( struct list *handler_list, ULONG first,
66 PVECTORED_EXCEPTION_HANDLER func )
68 VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
69 if (handler)
71 handler->func = RtlEncodePointer( func );
72 handler->count = 1;
73 RtlEnterCriticalSection( &vectored_handlers_section );
74 if (first) list_add_head( handler_list, &handler->entry );
75 else list_add_tail( handler_list, &handler->entry );
76 RtlLeaveCriticalSection( &vectored_handlers_section );
78 return handler;
82 static ULONG remove_vectored_handler( struct list *handler_list, VECTORED_HANDLER *handler )
84 struct list *ptr;
85 ULONG ret = FALSE;
87 RtlEnterCriticalSection( &vectored_handlers_section );
88 LIST_FOR_EACH( ptr, handler_list )
90 VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
91 if (curr_handler == handler)
93 if (!--curr_handler->count) list_remove( ptr );
94 else handler = NULL; /* don't free it yet */
95 ret = TRUE;
96 break;
99 RtlLeaveCriticalSection( &vectored_handlers_section );
100 if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
101 return ret;
105 /**********************************************************************
106 * wait_suspend
108 * Wait until the thread is no longer suspended.
110 void wait_suspend( CONTEXT *context )
112 LARGE_INTEGER timeout;
113 int saved_errno = errno;
114 context_t server_context;
115 DWORD flags = context->ContextFlags;
117 context_to_server( &server_context, context );
119 /* store the context we got at suspend time */
120 SERVER_START_REQ( set_suspend_context )
122 wine_server_add_data( req, &server_context, sizeof(server_context) );
123 wine_server_call( req );
125 SERVER_END_REQ;
127 /* wait with 0 timeout, will only return once the thread is no longer suspended */
128 timeout.QuadPart = 0;
129 server_select( NULL, 0, SELECT_INTERRUPTIBLE, &timeout );
131 /* retrieve the new context */
132 SERVER_START_REQ( get_suspend_context )
134 wine_server_set_reply( req, &server_context, sizeof(server_context) );
135 wine_server_call( req );
136 if (wine_server_reply_size( reply ))
138 context_from_server( context, &server_context );
139 context->ContextFlags |= flags; /* unchanged registers are still available */
142 SERVER_END_REQ;
144 errno = saved_errno;
148 /**********************************************************************
149 * send_debug_event
151 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
153 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
155 NTSTATUS ret;
156 DWORD i;
157 obj_handle_t handle = 0;
158 client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
159 context_t server_context;
160 select_op_t select_op;
162 if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */
164 for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
165 params[i] = rec->ExceptionInformation[i];
167 context_to_server( &server_context, context );
169 SERVER_START_REQ( queue_exception_event )
171 req->first = first_chance;
172 req->code = rec->ExceptionCode;
173 req->flags = rec->ExceptionFlags;
174 req->record = wine_server_client_ptr( rec->ExceptionRecord );
175 req->address = wine_server_client_ptr( rec->ExceptionAddress );
176 req->len = i * sizeof(params[0]);
177 wine_server_add_data( req, params, req->len );
178 wine_server_add_data( req, &server_context, sizeof(server_context) );
179 if (!wine_server_call( req )) handle = reply->handle;
181 SERVER_END_REQ;
182 if (!handle) return 0;
184 select_op.wait.op = SELECT_WAIT;
185 select_op.wait.handles[0] = handle;
186 server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, NULL );
188 SERVER_START_REQ( get_exception_status )
190 req->handle = handle;
191 wine_server_set_reply( req, &server_context, sizeof(server_context) );
192 ret = wine_server_call( req );
194 SERVER_END_REQ;
195 if (ret >= 0) context_from_server( context, &server_context );
196 return ret;
200 /**********************************************************************
201 * call_vectored_handlers
203 * Call the vectored handlers chain.
205 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
207 struct list *ptr;
208 LONG ret = EXCEPTION_CONTINUE_SEARCH;
209 EXCEPTION_POINTERS except_ptrs;
210 PVECTORED_EXCEPTION_HANDLER func;
211 VECTORED_HANDLER *handler, *to_free = NULL;
213 except_ptrs.ExceptionRecord = rec;
214 except_ptrs.ContextRecord = context;
216 RtlEnterCriticalSection( &vectored_handlers_section );
217 ptr = list_head( &vectored_exception_handlers );
218 while (ptr)
220 handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
221 handler->count++;
222 func = RtlDecodePointer( handler->func );
223 RtlLeaveCriticalSection( &vectored_handlers_section );
224 RtlFreeHeap( GetProcessHeap(), 0, to_free );
225 to_free = NULL;
227 TRACE( "calling handler at %p code=%x flags=%x\n",
228 func, rec->ExceptionCode, rec->ExceptionFlags );
229 ret = func( &except_ptrs );
230 TRACE( "handler at %p returned %x\n", func, ret );
232 RtlEnterCriticalSection( &vectored_handlers_section );
233 ptr = list_next( &vectored_exception_handlers, ptr );
234 if (!--handler->count) /* removed during execution */
236 list_remove( &handler->entry );
237 to_free = handler;
239 if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
241 RtlLeaveCriticalSection( &vectored_handlers_section );
242 RtlFreeHeap( GetProcessHeap(), 0, to_free );
243 return ret;
247 /*******************************************************************
248 * raise_status
250 * Implementation of RtlRaiseStatus with a specific exception record.
252 void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
254 EXCEPTION_RECORD ExceptionRec;
256 ExceptionRec.ExceptionCode = status;
257 ExceptionRec.ExceptionFlags = EH_NONCONTINUABLE;
258 ExceptionRec.ExceptionRecord = rec;
259 ExceptionRec.NumberParameters = 0;
260 for (;;) RtlRaiseException( &ExceptionRec ); /* never returns */
264 /***********************************************************************
265 * RtlRaiseStatus (NTDLL.@)
267 * Raise an exception with ExceptionCode = status
269 void WINAPI RtlRaiseStatus( NTSTATUS status )
271 raise_status( status, NULL );
275 /*******************************************************************
276 * RtlAddVectoredContinueHandler (NTDLL.@)
278 PVOID WINAPI RtlAddVectoredContinueHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
280 return add_vectored_handler( &vectored_continue_handlers, first, func );
284 /*******************************************************************
285 * RtlRemoveVectoredContinueHandler (NTDLL.@)
287 ULONG WINAPI RtlRemoveVectoredContinueHandler( PVOID handler )
289 return remove_vectored_handler( &vectored_continue_handlers, handler );
293 /*******************************************************************
294 * RtlAddVectoredExceptionHandler (NTDLL.@)
296 PVOID WINAPI DECLSPEC_HOTPATCH RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
298 return add_vectored_handler( &vectored_exception_handlers, first, func );
302 /*******************************************************************
303 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
305 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
307 return remove_vectored_handler( &vectored_exception_handlers, handler );
311 /*******************************************************************
312 * RtlSetUnhandledExceptionFilter (NTDLL.@)
314 void WINAPI RtlSetUnhandledExceptionFilter( PRTL_EXCEPTION_FILTER filter )
316 unhandled_exception_filter = filter;
320 /*******************************************************************
321 * call_unhandled_exception_filter
323 LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr )
325 if (!unhandled_exception_filter) return EXCEPTION_CONTINUE_SEARCH;
326 return unhandled_exception_filter( eptr );
330 /*************************************************************
331 * __wine_spec_unimplemented_stub
333 * ntdll-specific implementation to avoid depending on kernel functions.
334 * Can be removed once ntdll.spec no longer contains stubs.
336 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
338 EXCEPTION_RECORD record;
340 record.ExceptionCode = EXCEPTION_WINE_STUB;
341 record.ExceptionFlags = EH_NONCONTINUABLE;
342 record.ExceptionRecord = NULL;
343 record.ExceptionAddress = __wine_spec_unimplemented_stub;
344 record.NumberParameters = 2;
345 record.ExceptionInformation[0] = (ULONG_PTR)module;
346 record.ExceptionInformation[1] = (ULONG_PTR)function;
347 for (;;) RtlRaiseException( &record );
351 /*************************************************************
352 * IsBadStringPtrA
354 * IsBadStringPtrA replacement for ntdll, to catch exception in debug traces.
356 BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT_PTR max )
358 if (!str) return TRUE;
359 __TRY
361 volatile const char *p = str;
362 while (p != str + max) if (!*p++) break;
364 __EXCEPT_PAGE_FAULT
366 return TRUE;
368 __ENDTRY
369 return FALSE;
373 /*************************************************************
374 * IsBadStringPtrW
376 * IsBadStringPtrW replacement for ntdll, to catch exception in debug traces.
378 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT_PTR max )
380 if (!str) return TRUE;
381 __TRY
383 volatile const WCHAR *p = str;
384 while (p != str + max) if (!*p++) break;
386 __EXCEPT_PAGE_FAULT
388 return TRUE;
390 __ENDTRY
391 return FALSE;