Thomas Weidenmueller w3seek@reactos.com - Implement support for vectored exception handlers. - Add code for querying process cookie. Modified: trunk/reactos/include/ntdll/rtl.h Modified: trunk/reactos/include/ntos/zwtypes.h Modified: trunk/reactos/lib/ntdll/def/ntdll.def Modified: trunk/reactos/lib/ntdll/ldr/startup.c Modified: trunk/reactos/lib/ntdll/rtl/exception.c Modified: trunk/reactos/lib/ntdll/rtl/misc.c Modified: trunk/reactos/ntoskrnl/include/internal/ps.h Modified: trunk/reactos/ntoskrnl/ps/process.c _____
Modified: trunk/reactos/include/ntdll/rtl.h --- trunk/reactos/include/ntdll/rtl.h 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/include/ntdll/rtl.h 2005-03-12 08:54:41 UTC (rev 13962) @@ -770,7 +770,14 @@
STDCALL RtlDeleteTimerQueue(HANDLE TimerQueue);
+PVOID +STDCALL +RtlEncodePointer(IN PVOID Pointer);
+PVOID +STDCALL +RtlDecodePointer(IN PVOID Pointer); + #ifndef __NTDRIVER__
#ifndef __INTERLOCKED_DECLARED _____
Modified: trunk/reactos/include/ntos/zwtypes.h --- trunk/reactos/include/ntos/zwtypes.h 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/include/ntos/zwtypes.h 2005-03-12 08:54:41 UTC (rev 13962) @@ -1219,9 +1219,17 @@
#define ProcessSessionInformation 24 #define ProcessForegroundInformation 25 #define ProcessWow64Information 26 -/* ReactOS private. */ #define ProcessImageFileName 27 -#define MaxProcessInfoClass 28 +#define ProcessLUIDDeviceMapsEnabled 28 +#define ProcessBreakOnTermination 29 +#define ProcessDebugObjectHandle 30 +#define ProcessDebugFlags 31 +#define ProcessHandleTracing 32 +#define ProcessUnknown33 33 +#define ProcessUnknown34 34 +#define ProcessUnknown35 35 +#define ProcessCookie 36 +#define MaxProcessInfoClass 36
/* * thread query / set information class _____
Modified: trunk/reactos/lib/ntdll/def/ntdll.def --- trunk/reactos/lib/ntdll/def/ntdll.def 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/lib/ntdll/def/ntdll.def 2005-03-12 08:54:41 UTC (rev 13962) @@ -225,7 +225,6 @@
NtSetEvent@8 NtSetHighEventPair@4 NtSetHighWaitLowEventPair@4 -NtSetHighWaitLowThread@0 NtSetInformationFile@20 NtSetInformationJobObject@16 NtSetInformationKey@16 @@ -238,7 +237,6 @@ NtSetLdtEntries@24 NtSetLowEventPair@4 NtSetLowWaitHighEventPair@4 -NtSetLowWaitHighThread@0 NtSetSecurityObject@12 NtSetSystemEnvironmentValue@8 NtSetSystemInformation@12 @@ -298,6 +296,7 @@ RtlAddAuditAccessAceEx@28 ;RtlAddCompoundAce RtlAddRange@36 +RtlAddVectoredExceptionHandler@8 RtlAdjustPrivilege@16 RtlAllocateAndInitializeSid@44 RtlAllocateHandle@8 @@ -364,6 +363,7 @@ RtlCustomCPToUnicodeN@24 RtlCutoverTimeToSystemTime@16 RtlDeNormalizeProcessParams@4 +RtlDecodePointer=RtlEncodePointer@4 RtlDecompressBuffer@24 RtlDecompressFragment@32 RtlDelete@4 @@ -396,6 +396,7 @@ RtlDumpResource@4 RtlDuplicateUnicodeString@12 RtlEmptyAtomTable@8 +RtlEncodePointer@4 RtlEnlargedIntegerMultiply@8 RtlEnlargedUnsignedDivide@16 RtlEnlargedUnsignedMultiply@8 @@ -593,6 +594,7 @@ RtlReleasePebLock@0 RtlReleaseResource@4 ;RtlRemoteCall +RtlRemoveVectoredExceptionHandler@4 RtlResetRtlTranslations@4 RtlRestoreLastWin32Error@4=RtlSetLastWin32Error@4 RtlRunDecodeUnicodeString@8 @@ -849,7 +851,6 @@ ZwSetEvent@8 ZwSetHighEventPair@4 ZwSetHighWaitLowEventPair@4 -ZwSetHighWaitLowThread@0 ZwSetInformationFile@20 ZwSetInformationKey@16 ZwSetInformationObject@16 @@ -861,7 +862,6 @@ ZwSetLdtEntries@24 ZwSetLowEventPair@4 ZwSetLowWaitHighEventPair@4 -ZwSetLowWaitHighThread@0 ZwSetSecurityObject@12 ZwSetSystemEnvironmentValue@8 ZwSetSystemInformation@12 _____
Modified: trunk/reactos/lib/ntdll/ldr/startup.c --- trunk/reactos/lib/ntdll/ldr/startup.c 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/lib/ntdll/ldr/startup.c 2005-03-12 08:54:41 UTC (rev 13962) @@ -39,7 +39,9 @@
NTSTATUS LdrpAttachThread (VOID);
+VOID RtlpInitializeVectoredExceptionHandling(VOID);
+ #define VALUE_BUFFER_SIZE 256
BOOLEAN FASTCALL @@ -306,6 +308,9 @@ ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL); }
+ /* initialized vectored exception handling */ + RtlpInitializeVectoredExceptionHandling(); + /* initalize peb lock support */ RtlInitializeCriticalSection (&PebLock); Peb->FastPebLock = &PebLock; _____
Modified: trunk/reactos/lib/ntdll/rtl/exception.c --- trunk/reactos/lib/ntdll/rtl/exception.c 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/lib/ntdll/rtl/exception.c 2005-03-12 08:54:41 UTC (rev 13962) @@ -22,6 +22,19 @@
#define NDEBUG #include <debug.h>
+static CRITICAL_SECTION RtlpVectoredExceptionLock; +static LIST_ENTRY RtlpVectoredExceptionHead; + +typedef struct _RTL_VECTORED_EXCEPTION_HANDLER +{ + LIST_ENTRY ListEntry; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; +} RTL_VECTORED_EXCEPTION_HANDLER, *PRTL_VECTORED_EXCEPTION_HANDLER; + +/* FIXME - stupid ld won't resolve RtlDecodePointer! Since their implementation + is the same just use RtlEncodePointer for now! */ +#define RtlDecodePointer RtlEncodePointer + /* FUNCTIONS ***************************************************************/
VOID STDCALL @@ -35,20 +48,63 @@ RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context);
+EXCEPTION_DISPOSITION +RtlpExecuteVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_EXCEPTION_HANDLER veh; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; + EXCEPTION_POINTERS ExceptionInfo; + + ExceptionInfo.ExceptionRecord = ExceptionRecord; + ExceptionInfo.ContextRecord = Context; + + if(RtlpVectoredExceptionHead.Flink != &RtlpVectoredExceptionHead) + { + RtlEnterCriticalSection(&RtlpVectoredExceptionLock); + for(CurrentEntry = RtlpVectoredExceptionHead.Flink; + CurrentEntry != &RtlpVectoredExceptionHead; + CurrentEntry = CurrentEntry->Flink) + { + veh = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_EXCEPTION_HANDLER, + ListEntry); + VectoredHandler = RtlDecodePointer(veh->VectoredHandler); + if(VectoredHandler(&ExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION) + { + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + return ExceptionContinueSearch; + } + } + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + } + + return ExceptionContinueExecution; +} + VOID STDCALL KiUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context) { EXCEPTION_RECORD NestedExceptionRecord; NTSTATUS Status; - - if (RtlpDispatchException(ExceptionRecord, Context) != ExceptionContinueExecution) + + if(RtlpExecuteVectoredExceptionHandlers(ExceptionRecord, + Context) != ExceptionContinueExecution) { Status = NtContinue(Context, FALSE); } else { - Status = NtRaiseException(ExceptionRecord, Context, FALSE); + if(RtlpDispatchException(ExceptionRecord, Context) != ExceptionContinueExecution) + { + Status = NtContinue(Context, FALSE); + } + else + { + Status = NtRaiseException(ExceptionRecord, Context, FALSE); + } }
NestedExceptionRecord.ExceptionCode = Status; @@ -87,4 +143,83 @@ NtTerminateProcess(NtCurrentProcess(), ExitStatus); }
+ +VOID +RtlpInitializeVectoredExceptionHandling(VOID) +{ + InitializeListHead(&RtlpVectoredExceptionHead); + RtlInitializeCriticalSection(&RtlpVectoredExceptionLock); +} + + +/* + * @implemented + */ +PVOID STDCALL +RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +{ + PRTL_VECTORED_EXCEPTION_HANDLER veh; + + veh = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(RTL_VECTORED_EXCEPTION_HANDLER)); + if(veh != NULL) + { + veh->VectoredHandler = RtlEncodePointer(VectoredHandler); + RtlEnterCriticalSection(&RtlpVectoredExceptionLock); + if(FirstHandler != 0) + { + InsertHeadList(&RtlpVectoredExceptionHead, + &veh->ListEntry); + } + else + { + InsertTailList(&RtlpVectoredExceptionHead, + &veh->ListEntry); + } + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + } + + return veh; +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) +{ + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_EXCEPTION_HANDLER veh = NULL; + ULONG Removed = FALSE; + + RtlEnterCriticalSection(&RtlpVectoredExceptionLock); + for(CurrentEntry = RtlpVectoredExceptionHead.Flink; + CurrentEntry != &RtlpVectoredExceptionHead; + CurrentEntry = CurrentEntry->Flink) + { + veh = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_EXCEPTION_HANDLER, + ListEntry); + if(veh == VectoredHandlerHandle) + { + RemoveEntryList(&veh->ListEntry); + Removed = TRUE; + break; + } + } + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + + if(Removed) + { + RtlFreeHeap(RtlGetProcessHeap(), + 0, + veh); + } + + return Removed; +} + /* EOF */ _____
Modified: trunk/reactos/lib/ntdll/rtl/misc.c --- trunk/reactos/lib/ntdll/rtl/misc.c 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/lib/ntdll/rtl/misc.c 2005-03-12 08:54:41 UTC (rev 13962) @@ -15,6 +15,9 @@
#include <ddk/ntddk.h> #include <ntdll/rtl.h>
+#define NDEBUG +#include <ntdll/ntdll.h> + /********************************************************************** * NAME EXPORTED * RtlGetNtProductType @@ -107,3 +110,30 @@ PPEB pPeb = NtCurrentPeb(); return pPeb->NtGlobalFlag; } + + +/* + * @implemented + */ +PVOID +STDCALL +RtlEncodePointer(IN PVOID Pointer) +{ + ULONG Cookie; + NTSTATUS Status; + + Status = NtQueryInformationProcess(NtCurrentProcess(), + ProcessCookie, + &Cookie, + sizeof(Cookie), + NULL); + + if(!NT_SUCCESS(Status)) + { + DPRINT1("Failed to receive the process cookie! Status: 0x%x\n", Status); + return Pointer; + } + + return (PVOID)((ULONG_PTR)Pointer ^ Cookie); +} + _____
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h --- trunk/reactos/ntoskrnl/include/internal/ps.h 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/ntoskrnl/include/internal/ps.h 2005-03-12 08:54:41 UTC (rev 13962) @@ -416,6 +416,7 @@
PRTL_BITMAP VadPhysicalPagesBitMap; ULONG VadPhysicalPages; KSPIN_LOCK AweLock; + ULONG Cookie;
/* * FIXME - ReactOS specified - remove the following fields ASAP!!! _____
Modified: trunk/reactos/ntoskrnl/ps/process.c --- trunk/reactos/ntoskrnl/ps/process.c 2005-03-12 07:52:16 UTC (rev 13961) +++ trunk/reactos/ntoskrnl/ps/process.c 2005-03-12 08:54:41 UTC (rev 13962) @@ -67,6 +67,18 @@
ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */ ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */ ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */ + + /* FIXME */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessLUIDDeviceMapsEnabled */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessBreakOnTermination */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessDebugObjectHandle */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessDebugFlags */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessHandleTracing */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessUnknown33 */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessUnknown34 */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessUnknown35 */ + + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */ };
#define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8 @@ -1338,23 +1350,28 @@ DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status); return Status; } - - /* - * TODO: Here we should probably check that ProcessInformationLength - * bytes indeed are writable at address ProcessInformation. - */ - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_QUERY_INFORMATION, - PsProcessType, - PreviousMode, - (PVOID*)&Process, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - + + if(ProcessInformationClass != ProcessCookie) + { + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + PsProcessType, + PreviousMode, + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + } + else if(ProcessHandle != NtCurrentProcess()) + { + /* retreiving the process cookie is only allowed for the calling process + itself! XP only allowes NtCurrentProcess() as process handles even if a + real handle actually represents the current process. */ + return STATUS_INVALID_PARAMETER; + } + switch (ProcessInformationClass) { case ProcessBasicInformation: @@ -1731,7 +1748,61 @@ } break; } + + case ProcessCookie: + { + ULONG Cookie; + + /* receive the process cookie, this is only allowed for the current + process! */
+ Process = PsGetCurrentProcess(); + + Cookie = Process->Cookie; + if(Cookie == 0) + { + LARGE_INTEGER SystemTime; + ULONG NewCookie; + PKPRCB Prcb; + + /* generate a new cookie */ + + KeQuerySystemTime(&SystemTime); + + Prcb = &KeGetCurrentKPCR()->PrcbData; + + NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^ + SystemTime.u.LowPart ^ SystemTime.u.HighPart; + + /* try to set the new cookie, return the current one if another thread + set it in the meanwhile */ + Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie, + NewCookie, + Cookie); + if(Cookie == 0) + { + /* successfully set the cookie */ + Cookie = NewCookie; + } + } + + _SEH_TRY + { + *(PULONG)ProcessInformation = Cookie; + if (ReturnLength) + { + *ReturnLength = sizeof(ULONG); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + break; + } + /* * Note: The following 10 information classes are verified to not be * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS; @@ -1750,7 +1821,11 @@ Status = STATUS_INVALID_INFO_CLASS; }
- ObDereferenceObject(Process); + if(ProcessInformationClass != ProcessCookie) + { + ObDereferenceObject(Process); + } + return Status; }