reactos/sdk/lib/rtl/vectoreh.c

340 lines
10 KiB
C

/*
* 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 <rtl.h>
#define NDEBUG
#include <debug.h>
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 */