hlink: Site data should only be set if the hlink has an HlinkSite.
[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 } VECTORED_HANDLER;
48
49 static struct list vectored_handlers = LIST_INIT(vectored_handlers);
50
51 static RTL_RWLOCK vectored_handlers_lock;
52
53 /**********************************************************************
54  *           exceptions_init
55  *
56  * Initialize read/write lock used by the vectored exception handling.
57  */
58 void exceptions_init(void)
59 {
60     RtlInitializeResource(&vectored_handlers_lock);
61 }
62
63 /**********************************************************************
64  *           wait_suspend
65  *
66  * Wait until the thread is no longer suspended.
67  */
68 void wait_suspend( CONTEXT *context )
69 {
70     LARGE_INTEGER timeout;
71     int saved_errno = errno;
72     context_t server_context;
73
74     context_to_server( &server_context, context );
75
76     /* store the context we got at suspend time */
77     SERVER_START_REQ( set_thread_context )
78     {
79         req->handle  = wine_server_obj_handle( GetCurrentThread() );
80         req->suspend = 1;
81         wine_server_add_data( req, &server_context, sizeof(server_context) );
82         wine_server_call( req );
83     }
84     SERVER_END_REQ;
85
86     /* wait with 0 timeout, will only return once the thread is no longer suspended */
87     timeout.QuadPart = 0;
88     NTDLL_wait_for_multiple_objects( 0, NULL, SELECT_INTERRUPTIBLE, &timeout, 0 );
89
90     /* retrieve the new context */
91     SERVER_START_REQ( get_thread_context )
92     {
93         req->handle  = wine_server_obj_handle( GetCurrentThread() );
94         req->suspend = 1;
95         wine_server_set_reply( req, &server_context, sizeof(server_context) );
96         wine_server_call( req );
97     }
98     SERVER_END_REQ;
99
100     context_from_server( context, &server_context );
101     errno = saved_errno;
102 }
103
104
105 /**********************************************************************
106  *           send_debug_event
107  *
108  * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
109  */
110 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
111 {
112     NTSTATUS ret;
113     DWORD i;
114     HANDLE handle = 0;
115     client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
116     context_t server_context;
117
118     if (!NtCurrentTeb()->Peb->BeingDebugged) return 0;  /* no debugger present */
119
120     for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
121         params[i] = rec->ExceptionInformation[i];
122
123     context_to_server( &server_context, context );
124
125     SERVER_START_REQ( queue_exception_event )
126     {
127         req->first   = first_chance;
128         req->code    = rec->ExceptionCode;
129         req->flags   = rec->ExceptionFlags;
130         req->record  = wine_server_client_ptr( rec->ExceptionRecord );
131         req->address = wine_server_client_ptr( rec->ExceptionAddress );
132         req->len     = i * sizeof(params[0]);
133         wine_server_add_data( req, params, req->len );
134         wine_server_add_data( req, &server_context, sizeof(server_context) );
135         if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
136     }
137     SERVER_END_REQ;
138     if (!handle) return 0;
139
140     NTDLL_wait_for_multiple_objects( 1, &handle, SELECT_INTERRUPTIBLE, NULL, 0 );
141
142     SERVER_START_REQ( get_exception_status )
143     {
144         req->handle = wine_server_obj_handle( handle );
145         wine_server_set_reply( req, &server_context, sizeof(server_context) );
146         ret = wine_server_call( req );
147     }
148     SERVER_END_REQ;
149     if (ret >= 0) context_from_server( context, &server_context );
150     return ret;
151 }
152
153
154 /**********************************************************************
155  *           call_vectored_handlers
156  *
157  * Call the vectored handlers chain.
158  */
159 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
160 {
161     struct list *ptr;
162     LONG ret = EXCEPTION_CONTINUE_SEARCH;
163     EXCEPTION_POINTERS except_ptrs;
164
165     except_ptrs.ExceptionRecord = rec;
166     except_ptrs.ContextRecord = context;
167
168     RtlAcquireResourceShared( &vectored_handlers_lock, TRUE );
169     LIST_FOR_EACH( ptr, &vectored_handlers )
170     {
171         VECTORED_HANDLER *handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
172         TRACE( "calling handler at %p code=%x flags=%x\n",
173                handler->func, rec->ExceptionCode, rec->ExceptionFlags );
174         ret = handler->func( &except_ptrs );
175         TRACE( "handler at %p returned %x\n", handler->func, ret );
176         if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
177     }
178     RtlReleaseResource( &vectored_handlers_lock );
179     return ret;
180 }
181
182
183 /*******************************************************************
184  *              raise_status
185  *
186  * Implementation of RtlRaiseStatus with a specific exception record.
187  */
188 void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
189 {
190     EXCEPTION_RECORD ExceptionRec;
191
192     ExceptionRec.ExceptionCode    = status;
193     ExceptionRec.ExceptionFlags   = EH_NONCONTINUABLE;
194     ExceptionRec.ExceptionRecord  = rec;
195     ExceptionRec.NumberParameters = 0;
196     for (;;) RtlRaiseException( &ExceptionRec );  /* never returns */
197 }
198
199
200 /***********************************************************************
201  *            RtlRaiseStatus  (NTDLL.@)
202  *
203  * Raise an exception with ExceptionCode = status
204  */
205 void WINAPI RtlRaiseStatus( NTSTATUS status )
206 {
207     raise_status( status, NULL );
208 }
209
210
211 /*******************************************************************
212  *         RtlAddVectoredExceptionHandler   (NTDLL.@)
213  */
214 PVOID WINAPI RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
215 {
216     VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
217     if (handler)
218     {
219         handler->func = func;
220         RtlAcquireResourceExclusive( &vectored_handlers_lock, TRUE );
221         if (first) list_add_head( &vectored_handlers, &handler->entry );
222         else list_add_tail( &vectored_handlers, &handler->entry );
223         RtlReleaseResource( &vectored_handlers_lock );
224     }
225     return handler;
226 }
227
228
229 /*******************************************************************
230  *         RtlRemoveVectoredExceptionHandler   (NTDLL.@)
231  */
232 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
233 {
234     struct list *ptr;
235     ULONG ret = FALSE;
236
237     RtlAcquireResourceExclusive( &vectored_handlers_lock, TRUE );
238     LIST_FOR_EACH( ptr, &vectored_handlers )
239     {
240         VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
241         if (curr_handler == handler)
242         {
243             list_remove( ptr );
244             ret = TRUE;
245             break;
246         }
247     }
248     RtlReleaseResource( &vectored_handlers_lock );
249     if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
250     return ret;
251 }
252
253
254 /*************************************************************
255  *            __wine_spec_unimplemented_stub
256  *
257  * ntdll-specific implementation to avoid depending on kernel functions.
258  * Can be removed once ntdll.spec no longer contains stubs.
259  */
260 void __wine_spec_unimplemented_stub( const char *module, const char *function )
261 {
262     EXCEPTION_RECORD record;
263
264     record.ExceptionCode    = EXCEPTION_WINE_STUB;
265     record.ExceptionFlags   = EH_NONCONTINUABLE;
266     record.ExceptionRecord  = NULL;
267     record.ExceptionAddress = __wine_spec_unimplemented_stub;
268     record.NumberParameters = 2;
269     record.ExceptionInformation[0] = (ULONG_PTR)module;
270     record.ExceptionInformation[1] = (ULONG_PTR)function;
271     for (;;) RtlRaiseException( &record );
272 }