2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS sysem libraries
4 * PURPOSE: Vectored Exception Handling
5 * FILE: lib/rtl/vectoreh.c
6 * PROGRAMERS: Thomas Weidenmueller
9 /* INCLUDES *****************************************************************/
16 RTL_CRITICAL_SECTION RtlpVectoredHandlerLock
;
17 LIST_ENTRY RtlpVectoredExceptionList
, RtlpVectoredContinueList
;
19 typedef struct _RTL_VECTORED_HANDLER_ENTRY
22 PVECTORED_EXCEPTION_HANDLER VectoredHandler
;
24 } RTL_VECTORED_HANDLER_ENTRY
, *PRTL_VECTORED_HANDLER_ENTRY
;
26 /* FUNCTIONS ***************************************************************/
30 RtlpInitializeVectoredExceptionHandling(VOID
)
32 /* Initialize our two lists and the common lock */
33 RtlInitializeCriticalSection(&RtlpVectoredHandlerLock
);
34 InitializeListHead(&RtlpVectoredExceptionList
);
35 InitializeListHead(&RtlpVectoredContinueList
);
40 RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord
,
42 IN PLIST_ENTRY VectoredHandlerList
)
44 PLIST_ENTRY CurrentEntry
;
45 PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler
;
46 PVECTORED_EXCEPTION_HANDLER VectoredHandler
;
47 EXCEPTION_POINTERS ExceptionInfo
;
48 BOOLEAN HandlerRemoved
;
52 * Initialize these in case there are no entries,
53 * or if no one handled the exception
55 HandlerRemoved
= FALSE
;
56 HandlerReturn
= EXCEPTION_CONTINUE_SEARCH
;
58 /* Set up the data to pass to the handler */
59 ExceptionInfo
.ExceptionRecord
= ExceptionRecord
;
60 ExceptionInfo
.ContextRecord
= Context
;
63 RtlEnterCriticalSection(&RtlpVectoredHandlerLock
);
66 CurrentEntry
= VectoredHandlerList
->Flink
;
67 while (CurrentEntry
!= VectoredHandlerList
)
70 VectoredExceptionHandler
= CONTAINING_RECORD(CurrentEntry
,
71 RTL_VECTORED_HANDLER_ENTRY
,
74 /* Reference it so it doesn't go away while we are using it */
75 VectoredExceptionHandler
->Refs
++;
77 /* Drop the lock before calling the handler */
78 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock
);
81 * Get the function pointer, decoding it so we will crash
82 * if malicious code has altered it. That is, if something has
83 * set VectoredHandler to a non-encoded pointer
85 VectoredHandler
= RtlDecodePointer(VectoredExceptionHandler
->VectoredHandler
);
87 /* Call the handler */
88 HandlerReturn
= VectoredHandler(&ExceptionInfo
);
90 /* Handler called -- grab the lock to dereference */
91 RtlEnterCriticalSection(&RtlpVectoredHandlerLock
);
93 /* Dereference and see if it got deleted */
94 VectoredExceptionHandler
->Refs
--;
95 if (VectoredExceptionHandler
->Refs
== 0)
97 /* It did -- do we have to free it now? */
98 if (HandlerReturn
== EXCEPTION_CONTINUE_EXECUTION
)
100 /* We don't, just remove it from the list and break out */
101 RemoveEntryList(&VectoredExceptionHandler
->ListEntry
);
102 HandlerRemoved
= TRUE
;
107 * Get the next entry before freeing,
108 * and remove the current one from the list
110 CurrentEntry
= VectoredExceptionHandler
->ListEntry
.Flink
;
111 RemoveEntryList(&VectoredExceptionHandler
->ListEntry
);
113 /* Free the entry outside of the lock, then reacquire it */
114 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock
);
115 RtlFreeHeap(RtlGetProcessHeap(),
117 VectoredExceptionHandler
);
118 RtlEnterCriticalSection(&RtlpVectoredHandlerLock
);
122 /* No delete -- should we continue execution? */
123 if (HandlerReturn
== EXCEPTION_CONTINUE_EXECUTION
)
130 /* Continue searching the list */
131 CurrentEntry
= CurrentEntry
->Flink
;
136 /* Let go of the lock now */
137 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock
);
139 /* Anything to free? */
143 RtlFreeHeap(RtlGetProcessHeap(),
145 VectoredExceptionHandler
);
148 /* Return whether to continue execution (ignored for continue handlers) */
149 return (HandlerReturn
== EXCEPTION_CONTINUE_EXECUTION
) ? TRUE
: FALSE
;
154 RtlpAddVectoredHandler(IN ULONG FirstHandler
,
155 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler
,
156 IN PLIST_ENTRY VectoredHandlerList
)
158 PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry
;
160 /* Allocate our structure */
161 VectoredHandlerEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
163 sizeof(RTL_VECTORED_HANDLER_ENTRY
));
164 if (!VectoredHandlerEntry
) return NULL
;
166 /* Set it up, encoding the pointer for security */
167 VectoredHandlerEntry
->VectoredHandler
= RtlEncodePointer(VectoredHandler
);
168 VectoredHandlerEntry
->Refs
= 1;
170 /* Lock the list before modifying it */
171 RtlEnterCriticalSection(&RtlpVectoredHandlerLock
);
174 * While holding the list lock, insert the handler
175 * at beginning or end of list according to caller.
179 InsertHeadList(VectoredHandlerList
,
180 &VectoredHandlerEntry
->ListEntry
);
184 InsertTailList(VectoredHandlerList
,
185 &VectoredHandlerEntry
->ListEntry
);
188 /* Done with the list, unlock it */
189 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock
);
191 /* Return pointer to the structure as the handle */
192 return VectoredHandlerEntry
;
197 RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle
,
198 IN PLIST_ENTRY VectoredHandlerList
)
200 PLIST_ENTRY CurrentEntry
;
201 PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler
;
202 BOOLEAN HandlerRemoved
;
203 BOOLEAN HandlerFound
;
205 /* Initialize these in case we don't find anything */
206 HandlerRemoved
= FALSE
;
207 HandlerFound
= FALSE
;
209 /* Acquire list lock */
210 RtlEnterCriticalSection(&RtlpVectoredHandlerLock
);
213 CurrentEntry
= VectoredHandlerList
->Flink
;
214 while (CurrentEntry
!= VectoredHandlerList
)
217 VectoredExceptionHandler
= CONTAINING_RECORD(CurrentEntry
,
218 RTL_VECTORED_HANDLER_ENTRY
,
222 if (VectoredExceptionHandler
== VectoredHandlerHandle
)
225 * Great, this means it is a valid entry.
226 * However, it may be in use by the exception
227 * dispatcher, so we have a ref count to respect.
228 * If we can't remove it now then it will be done
229 * right after it is not in use anymore.
231 * Caller is supposed to keep track of if it has deleted the
232 * entry and should not call us twice for the same entry.
233 * We could maybe throw in some kind of ASSERT to detect this
234 * if this was to become a problem.
236 VectoredExceptionHandler
->Refs
--;
237 if (VectoredExceptionHandler
->Refs
== 0)
239 /* Not in use, ok to remove and free */
240 RemoveEntryList(&VectoredExceptionHandler
->ListEntry
);
241 HandlerRemoved
= TRUE
;
244 /* Found what we are looking for, stop searching */
250 /* Get the next entry */
251 CurrentEntry
= CurrentEntry
->Flink
;
255 /* Done with the list, let go of the lock */
256 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock
);
258 /* Can we free what we found? */
262 RtlFreeHeap(RtlGetProcessHeap(),
264 VectoredExceptionHandler
);
267 /* Return whether we found it */
268 return (ULONG
)HandlerFound
;
273 RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord
,
276 /* Call the shared routine */
277 return RtlpCallVectoredHandlers(ExceptionRecord
,
279 &RtlpVectoredExceptionList
);
284 RtlCallVectoredContinueHandlers(IN PEXCEPTION_RECORD ExceptionRecord
,
288 * Call the shared routine (ignoring result,
289 * execution always continues at this point)
291 (VOID
)RtlpCallVectoredHandlers(ExceptionRecord
,
293 &RtlpVectoredContinueList
);
299 RtlAddVectoredExceptionHandler(IN ULONG FirstHandler
,
300 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler
)
302 /* Call the shared routine */
303 return RtlpAddVectoredHandler(FirstHandler
,
305 &RtlpVectoredExceptionList
);
311 RtlAddVectoredContinueHandler(IN ULONG FirstHandler
,
312 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler
)
314 /* Call the shared routine */
315 return RtlpAddVectoredHandler(FirstHandler
,
317 &RtlpVectoredContinueList
);
323 RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle
)
325 /* Call the shared routine */
326 return RtlpRemoveVectoredHandler(VectoredHandlerHandle
,
327 &RtlpVectoredExceptionList
);
333 RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle
)
335 /* Call the shared routine */
336 return RtlpRemoveVectoredHandler(VectoredHandlerHandle
,
337 &RtlpVectoredContinueList
);