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;
 }