ntdll: Specify div to be divl.
[wine] / dlls / ntdll / exception.c
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     VECTORED_HANDLER *handler, *to_free = NULL;
159
160     except_ptrs.ExceptionRecord = rec;
161     except_ptrs.ContextRecord = context;
162
163     RtlEnterCriticalSection( &vectored_handlers_section );
164     ptr = list_head( &vectored_handlers );
165     while (ptr)
166     {
167         handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
168         handler->count++;
169         RtlLeaveCriticalSection( &vectored_handlers_section );
170         RtlFreeHeap( GetProcessHeap(), 0, to_free );
171         to_free = NULL;
172
173         TRACE( "calling handler at %p code=%x flags=%x\n",
174                handler->func, rec->ExceptionCode, rec->ExceptionFlags );
175         ret = handler->func( &except_ptrs );
176         TRACE( "handler at %p returned %x\n", handler->func, ret );
177
178         RtlEnterCriticalSection( &vectored_handlers_section );
179         ptr = list_next( &vectored_handlers, ptr );
180         if (!--handler->count)  /* removed during execution */
181         {
182             list_remove( &handler->entry );
183             to_free = handler;
184         }
185         if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
186     }
187     RtlLeaveCriticalSection( &vectored_handlers_section );
188     RtlFreeHeap( GetProcessHeap(), 0, to_free );
189     return ret;
190 }
191
192
193 /*******************************************************************
194  *              raise_status
195  *
196  * Implementation of RtlRaiseStatus with a specific exception record.
197  */
198 void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
199 {
200     EXCEPTION_RECORD ExceptionRec;
201
202     ExceptionRec.ExceptionCode    = status;
203     ExceptionRec.ExceptionFlags   = EH_NONCONTINUABLE;
204     ExceptionRec.ExceptionRecord  = rec;
205     ExceptionRec.NumberParameters = 0;
206     for (;;) RtlRaiseException( &ExceptionRec );  /* never returns */
207 }
208
209
210 /***********************************************************************
211  *            RtlRaiseStatus  (NTDLL.@)
212  *
213  * Raise an exception with ExceptionCode = status
214  */
215 void WINAPI RtlRaiseStatus( NTSTATUS status )
216 {
217     raise_status( status, NULL );
218 }
219
220
221 /*******************************************************************
222  *         RtlAddVectoredExceptionHandler   (NTDLL.@)
223  */
224 PVOID WINAPI RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
225 {
226     VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
227     if (handler)
228     {
229         handler->func = func;
230         handler->count = 1;
231         RtlEnterCriticalSection( &vectored_handlers_section );
232         if (first) list_add_head( &vectored_handlers, &handler->entry );
233         else list_add_tail( &vectored_handlers, &handler->entry );
234         RtlLeaveCriticalSection( &vectored_handlers_section );
235     }
236     return handler;
237 }
238
239
240 /*******************************************************************
241  *         RtlRemoveVectoredExceptionHandler   (NTDLL.@)
242  */
243 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
244 {
245     struct list *ptr;
246     ULONG ret = FALSE;
247
248     RtlEnterCriticalSection( &vectored_handlers_section );
249     LIST_FOR_EACH( ptr, &vectored_handlers )
250     {
251         VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
252         if (curr_handler == handler)
253         {
254             if (!--curr_handler->count) list_remove( ptr );
255             else handler = NULL;  /* don't free it yet */
256             ret = TRUE;
257             break;
258         }
259     }
260     RtlLeaveCriticalSection( &vectored_handlers_section );
261     if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
262     return ret;
263 }
264
265
266 /*************************************************************
267  *            __wine_spec_unimplemented_stub
268  *
269  * ntdll-specific implementation to avoid depending on kernel functions.
270  * Can be removed once ntdll.spec no longer contains stubs.
271  */
272 void __wine_spec_unimplemented_stub( const char *module, const char *function )
273 {
274     EXCEPTION_RECORD record;
275
276     record.ExceptionCode    = EXCEPTION_WINE_STUB;
277     record.ExceptionFlags   = EH_NONCONTINUABLE;
278     record.ExceptionRecord  = NULL;
279     record.ExceptionAddress = __wine_spec_unimplemented_stub;
280     record.NumberParameters = 2;
281     record.ExceptionInformation[0] = (ULONG_PTR)module;
282     record.ExceptionInformation[1] = (ULONG_PTR)function;
283     for (;;) RtlRaiseException( &record );
284 }