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
23 #include "wine/port.h"
31 #define WIN32_NO_STATUS
34 #include "wine/exception.h"
35 #include "wine/server.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 #include "ntdll_misc.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
46 PVECTORED_EXCEPTION_HANDLER func
;
50 static struct list vectored_handlers
= LIST_INIT(vectored_handlers
);
52 static RTL_CRITICAL_SECTION vectored_handlers_section
;
53 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
55 0, 0, &vectored_handlers_section
,
56 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
57 0, 0, { (DWORD_PTR
)(__FILE__
": vectored_handlers_section") }
59 static RTL_CRITICAL_SECTION vectored_handlers_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
61 /**********************************************************************
64 * Wait until the thread is no longer suspended.
66 void wait_suspend( CONTEXT
*context
)
68 LARGE_INTEGER timeout
;
69 int saved_errno
= errno
;
70 context_t server_context
;
72 context_to_server( &server_context
, context
);
74 /* store the context we got at suspend time */
75 SERVER_START_REQ( set_thread_context
)
77 req
->handle
= wine_server_obj_handle( GetCurrentThread() );
79 wine_server_add_data( req
, &server_context
, sizeof(server_context
) );
80 wine_server_call( req
);
84 /* wait with 0 timeout, will only return once the thread is no longer suspended */
86 NTDLL_wait_for_multiple_objects( 0, NULL
, SELECT_INTERRUPTIBLE
, &timeout
, 0 );
88 /* retrieve the new context */
89 SERVER_START_REQ( get_thread_context
)
91 req
->handle
= wine_server_obj_handle( GetCurrentThread() );
93 wine_server_set_reply( req
, &server_context
, sizeof(server_context
) );
94 wine_server_call( req
);
98 context_from_server( context
, &server_context
);
103 /**********************************************************************
106 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
108 NTSTATUS
send_debug_event( EXCEPTION_RECORD
*rec
, int first_chance
, CONTEXT
*context
)
113 client_ptr_t params
[EXCEPTION_MAXIMUM_PARAMETERS
];
114 context_t server_context
;
116 if (!NtCurrentTeb()->Peb
->BeingDebugged
) return 0; /* no debugger present */
118 for (i
= 0; i
< min( rec
->NumberParameters
, EXCEPTION_MAXIMUM_PARAMETERS
); i
++)
119 params
[i
] = rec
->ExceptionInformation
[i
];
121 context_to_server( &server_context
, context
);
123 SERVER_START_REQ( queue_exception_event
)
125 req
->first
= first_chance
;
126 req
->code
= rec
->ExceptionCode
;
127 req
->flags
= rec
->ExceptionFlags
;
128 req
->record
= wine_server_client_ptr( rec
->ExceptionRecord
);
129 req
->address
= wine_server_client_ptr( rec
->ExceptionAddress
);
130 req
->len
= i
* sizeof(params
[0]);
131 wine_server_add_data( req
, params
, req
->len
);
132 wine_server_add_data( req
, &server_context
, sizeof(server_context
) );
133 if (!wine_server_call( req
)) handle
= wine_server_ptr_handle( reply
->handle
);
136 if (!handle
) return 0;
138 NTDLL_wait_for_multiple_objects( 1, &handle
, SELECT_INTERRUPTIBLE
, NULL
, 0 );
140 SERVER_START_REQ( get_exception_status
)
142 req
->handle
= wine_server_obj_handle( handle
);
143 wine_server_set_reply( req
, &server_context
, sizeof(server_context
) );
144 ret
= wine_server_call( req
);
147 if (ret
>= 0) context_from_server( context
, &server_context
);
152 /**********************************************************************
153 * call_vectored_handlers
155 * Call the vectored handlers chain.
157 LONG
call_vectored_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
160 LONG ret
= EXCEPTION_CONTINUE_SEARCH
;
161 EXCEPTION_POINTERS except_ptrs
;
162 VECTORED_HANDLER
*handler
, *to_free
= NULL
;
164 except_ptrs
.ExceptionRecord
= rec
;
165 except_ptrs
.ContextRecord
= context
;
167 RtlEnterCriticalSection( &vectored_handlers_section
);
168 ptr
= list_head( &vectored_handlers
);
171 handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
173 RtlLeaveCriticalSection( &vectored_handlers_section
);
174 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
177 TRACE( "calling handler at %p code=%x flags=%x\n",
178 handler
->func
, rec
->ExceptionCode
, rec
->ExceptionFlags
);
179 ret
= handler
->func( &except_ptrs
);
180 TRACE( "handler at %p returned %x\n", handler
->func
, ret
);
182 RtlEnterCriticalSection( &vectored_handlers_section
);
183 ptr
= list_next( &vectored_handlers
, ptr
);
184 if (!--handler
->count
) /* removed during execution */
186 list_remove( &handler
->entry
);
189 if (ret
== EXCEPTION_CONTINUE_EXECUTION
) break;
191 RtlLeaveCriticalSection( &vectored_handlers_section
);
192 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
197 /*******************************************************************
200 * Implementation of RtlRaiseStatus with a specific exception record.
202 void raise_status( NTSTATUS status
, EXCEPTION_RECORD
*rec
)
204 EXCEPTION_RECORD ExceptionRec
;
206 ExceptionRec
.ExceptionCode
= status
;
207 ExceptionRec
.ExceptionFlags
= EH_NONCONTINUABLE
;
208 ExceptionRec
.ExceptionRecord
= rec
;
209 ExceptionRec
.NumberParameters
= 0;
210 for (;;) RtlRaiseException( &ExceptionRec
); /* never returns */
214 /***********************************************************************
215 * RtlRaiseStatus (NTDLL.@)
217 * Raise an exception with ExceptionCode = status
219 void WINAPI
RtlRaiseStatus( NTSTATUS status
)
221 raise_status( status
, NULL
);
225 /*******************************************************************
226 * RtlAddVectoredExceptionHandler (NTDLL.@)
228 PVOID WINAPI
RtlAddVectoredExceptionHandler( ULONG first
, PVECTORED_EXCEPTION_HANDLER func
)
230 VECTORED_HANDLER
*handler
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler
) );
233 handler
->func
= func
;
235 RtlEnterCriticalSection( &vectored_handlers_section
);
236 if (first
) list_add_head( &vectored_handlers
, &handler
->entry
);
237 else list_add_tail( &vectored_handlers
, &handler
->entry
);
238 RtlLeaveCriticalSection( &vectored_handlers_section
);
244 /*******************************************************************
245 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
247 ULONG WINAPI
RtlRemoveVectoredExceptionHandler( PVOID handler
)
252 RtlEnterCriticalSection( &vectored_handlers_section
);
253 LIST_FOR_EACH( ptr
, &vectored_handlers
)
255 VECTORED_HANDLER
*curr_handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
256 if (curr_handler
== handler
)
258 if (!--curr_handler
->count
) list_remove( ptr
);
259 else handler
= NULL
; /* don't free it yet */
264 RtlLeaveCriticalSection( &vectored_handlers_section
);
265 if (ret
) RtlFreeHeap( GetProcessHeap(), 0, handler
);
270 /*************************************************************
271 * __wine_spec_unimplemented_stub
273 * ntdll-specific implementation to avoid depending on kernel functions.
274 * Can be removed once ntdll.spec no longer contains stubs.
276 void __wine_spec_unimplemented_stub( const char *module
, const char *function
)
278 EXCEPTION_RECORD record
;
280 record
.ExceptionCode
= EXCEPTION_WINE_STUB
;
281 record
.ExceptionFlags
= EH_NONCONTINUABLE
;
282 record
.ExceptionRecord
= NULL
;
283 record
.ExceptionAddress
= __wine_spec_unimplemented_stub
;
284 record
.NumberParameters
= 2;
285 record
.ExceptionInformation
[0] = (ULONG_PTR
)module
;
286 record
.ExceptionInformation
[1] = (ULONG_PTR
)function
;
287 for (;;) RtlRaiseException( &record
);