/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS sysem libraries * PURPOSE: Vectored Exception Handling * FILE: lib/rtl/vectoreh.c * PROGRAMERS: Thomas Weidenmueller */ /* INCLUDES *****************************************************************/ #include #define NDEBUG #include RTL_CRITICAL_SECTION RtlpVectoredHandlerLock; LIST_ENTRY RtlpVectoredExceptionList, RtlpVectoredContinueList; typedef struct _RTL_VECTORED_HANDLER_ENTRY { LIST_ENTRY ListEntry; PVECTORED_EXCEPTION_HANDLER VectoredHandler; ULONG Refs; } RTL_VECTORED_HANDLER_ENTRY, *PRTL_VECTORED_HANDLER_ENTRY; /* FUNCTIONS ***************************************************************/ VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID) { /* Initialize our two lists and the common lock */ RtlInitializeCriticalSection(&RtlpVectoredHandlerLock); InitializeListHead(&RtlpVectoredExceptionList); InitializeListHead(&RtlpVectoredContinueList); } BOOLEAN NTAPI RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context, IN PLIST_ENTRY VectoredHandlerList) { PLIST_ENTRY CurrentEntry; PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; PVECTORED_EXCEPTION_HANDLER VectoredHandler; EXCEPTION_POINTERS ExceptionInfo; BOOLEAN HandlerRemoved; LONG HandlerReturn; /* * Initialize these in case there are no entries, * or if no one handled the exception */ HandlerRemoved = FALSE; HandlerReturn = EXCEPTION_CONTINUE_SEARCH; /* Set up the data to pass to the handler */ ExceptionInfo.ExceptionRecord = ExceptionRecord; ExceptionInfo.ContextRecord = Context; /* Grab the lock */ RtlEnterCriticalSection(&RtlpVectoredHandlerLock); /* Loop entries */ CurrentEntry = VectoredHandlerList->Flink; while (CurrentEntry != VectoredHandlerList) { /* Get the struct */ VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, RTL_VECTORED_HANDLER_ENTRY, ListEntry); /* Reference it so it doesn't go away while we are using it */ VectoredExceptionHandler->Refs++; /* Drop the lock before calling the handler */ RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); /* * Get the function pointer, decoding it so we will crash * if malicious code has altered it. That is, if something has * set VectoredHandler to a non-encoded pointer */ VectoredHandler = RtlDecodePointer(VectoredExceptionHandler->VectoredHandler); /* Call the handler */ HandlerReturn = VectoredHandler(&ExceptionInfo); /* Handler called -- grab the lock to dereference */ RtlEnterCriticalSection(&RtlpVectoredHandlerLock); /* Dereference and see if it got deleted */ VectoredExceptionHandler->Refs--; if (VectoredExceptionHandler->Refs == 0) { /* It did -- do we have to free it now? */ if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) { /* We don't, just remove it from the list and break out */ RemoveEntryList(&VectoredExceptionHandler->ListEntry); HandlerRemoved = TRUE; break; } /* * Get the next entry before freeing, * and remove the current one from the list */ CurrentEntry = VectoredExceptionHandler->ListEntry.Flink; RemoveEntryList(&VectoredExceptionHandler->ListEntry); /* Free the entry outside of the lock, then reacquire it */ RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); RtlFreeHeap(RtlGetProcessHeap(), 0, VectoredExceptionHandler); RtlEnterCriticalSection(&RtlpVectoredHandlerLock); } else { /* No delete -- should we continue execution? */ if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) { /* Break out */ break; } else { /* Continue searching the list */ CurrentEntry = CurrentEntry->Flink; } } } /* Let go of the lock now */ RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); /* Anything to free? */ if (HandlerRemoved) { /* Get rid of it */ RtlFreeHeap(RtlGetProcessHeap(), 0, VectoredExceptionHandler); } /* Return whether to continue execution (ignored for continue handlers) */ return (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) ? TRUE : FALSE; } PVOID NTAPI RtlpAddVectoredHandler(IN ULONG FirstHandler, IN PVECTORED_EXCEPTION_HANDLER VectoredHandler, IN PLIST_ENTRY VectoredHandlerList) { PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry; /* Allocate our structure */ VectoredHandlerEntry = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_VECTORED_HANDLER_ENTRY)); if (!VectoredHandlerEntry) return NULL; /* Set it up, encoding the pointer for security */ VectoredHandlerEntry->VectoredHandler = RtlEncodePointer(VectoredHandler); VectoredHandlerEntry->Refs = 1; /* Lock the list before modifying it */ RtlEnterCriticalSection(&RtlpVectoredHandlerLock); /* * While holding the list lock, insert the handler * at beginning or end of list according to caller. */ if (FirstHandler) { InsertHeadList(VectoredHandlerList, &VectoredHandlerEntry->ListEntry); } else { InsertTailList(VectoredHandlerList, &VectoredHandlerEntry->ListEntry); } /* Done with the list, unlock it */ RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); /* Return pointer to the structure as the handle */ return VectoredHandlerEntry; } ULONG NTAPI RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle, IN PLIST_ENTRY VectoredHandlerList) { PLIST_ENTRY CurrentEntry; PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; BOOLEAN HandlerRemoved; BOOLEAN HandlerFound; /* Initialize these in case we don't find anything */ HandlerRemoved = FALSE; HandlerFound = FALSE; /* Acquire list lock */ RtlEnterCriticalSection(&RtlpVectoredHandlerLock); /* Loop the list */ CurrentEntry = VectoredHandlerList->Flink; while (CurrentEntry != VectoredHandlerList) { /* Get the struct */ VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, RTL_VECTORED_HANDLER_ENTRY, ListEntry); /* Does it match? */ if (VectoredExceptionHandler == VectoredHandlerHandle) { /* * Great, this means it is a valid entry. * However, it may be in use by the exception * dispatcher, so we have a ref count to respect. * If we can't remove it now then it will be done * right after it is not in use anymore. * * Caller is supposed to keep track of if it has deleted the * entry and should not call us twice for the same entry. * We could maybe throw in some kind of ASSERT to detect this * if this was to become a problem. */ VectoredExceptionHandler->Refs--; if (VectoredExceptionHandler->Refs == 0) { /* Not in use, ok to remove and free */ RemoveEntryList(&VectoredExceptionHandler->ListEntry); HandlerRemoved = TRUE; } /* Found what we are looking for, stop searching */ HandlerFound = TRUE; break; } else { /* Get the next entry */ CurrentEntry = CurrentEntry->Flink; } } /* Done with the list, let go of the lock */ RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); /* Can we free what we found? */ if (HandlerRemoved) { /* Do it */ RtlFreeHeap(RtlGetProcessHeap(), 0, VectoredExceptionHandler); } /* Return whether we found it */ return (ULONG)HandlerFound; } BOOLEAN NTAPI RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context) { /* Call the shared routine */ return RtlpCallVectoredHandlers(ExceptionRecord, Context, &RtlpVectoredExceptionList); } VOID NTAPI RtlCallVectoredContinueHandlers(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context) { /* * Call the shared routine (ignoring result, * execution always continues at this point) */ (VOID)RtlpCallVectoredHandlers(ExceptionRecord, Context, &RtlpVectoredContinueList); } DECLSPEC_HOTPATCH PVOID NTAPI RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) { /* Call the shared routine */ return RtlpAddVectoredHandler(FirstHandler, VectoredHandler, &RtlpVectoredExceptionList); } DECLSPEC_HOTPATCH PVOID NTAPI RtlAddVectoredContinueHandler(IN ULONG FirstHandler, IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) { /* Call the shared routine */ return RtlpAddVectoredHandler(FirstHandler, VectoredHandler, &RtlpVectoredContinueList); } //DECLSPEC_HOTPATCH ULONG NTAPI RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) { /* Call the shared routine */ return RtlpRemoveVectoredHandler(VectoredHandlerHandle, &RtlpVectoredExceptionList); } //DECLSPEC_HOTPATCH ULONG NTAPI RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle) { /* Call the shared routine */ return RtlpRemoveVectoredHandler(VectoredHandlerHandle, &RtlpVectoredContinueList); } /* EOF */