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_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
) );
71 handler
->func
= RtlEncodePointer( func
);
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
);
82 static ULONG
remove_vectored_handler( struct list
*handler_list
, VECTORED_HANDLER
*handler
)
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 */
99 RtlLeaveCriticalSection( &vectored_handlers_section
);
100 if (ret
) RtlFreeHeap( GetProcessHeap(), 0, handler
);
105 /**********************************************************************
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
);
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 */
148 /**********************************************************************
151 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
153 NTSTATUS
send_debug_event( EXCEPTION_RECORD
*rec
, int first_chance
, CONTEXT
*context
)
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
;
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
);
195 if (ret
>= 0) context_from_server( context
, &server_context
);
200 /**********************************************************************
201 * call_vectored_handlers
203 * Call the vectored handlers chain.
205 LONG
call_vectored_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
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
);
220 handler
= LIST_ENTRY( ptr
, VECTORED_HANDLER
, entry
);
222 func
= RtlDecodePointer( handler
->func
);
223 RtlLeaveCriticalSection( &vectored_handlers_section
);
224 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
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
);
239 if (ret
== EXCEPTION_CONTINUE_EXECUTION
) break;
241 RtlLeaveCriticalSection( &vectored_handlers_section
);
242 RtlFreeHeap( GetProcessHeap(), 0, to_free
);
247 /*******************************************************************
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 /*************************************************************
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
;
361 volatile const char *p
= str
;
362 while (p
!= str
+ max
) if (!*p
++) break;
373 /*************************************************************
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
;
383 volatile const WCHAR
*p
= str
;
384 while (p
!= str
+ max
) if (!*p
++) break;