[ros-diffs] [ion] 24572: - Implement the entire kernel-mode native interface of Debug Objects, minus a few missing operations in NtWaitForDebugEvent: - NtCreateDebugObject, NtDebugContinue, NtDebugActiveProcess, NtRemoveProcessDebug, NtSetInformationDebugObject, NtWaitForDebugEvent. - Of course, the entire backend is stubbed out. - Implement Debug object initialization (not called yet) and close(not done) and delete (done) callbacks.

ion at svn.reactos.org ion at svn.reactos.org
Thu Oct 19 09:04:22 CEST 2006


Author: ion
Date: Thu Oct 19 11:04:21 2006
New Revision: 24572

URL: http://svn.reactos.org/svn/reactos?rev=24572&view=rev
Log:
- Implement the entire kernel-mode native interface of Debug Objects, minus a few missing operations in NtWaitForDebugEvent:
  - NtCreateDebugObject, NtDebugContinue, NtDebugActiveProcess, NtRemoveProcessDebug, NtSetInformationDebugObject, NtWaitForDebugEvent.
- Of course, the entire backend is stubbed out.
- Implement Debug object initialization (not called yet) and close(not done) and delete (done) callbacks.

Modified:
    trunk/reactos/include/ddk/ntstatus.h
    trunk/reactos/include/ndk/dbgktypes.h
    trunk/reactos/ntoskrnl/dbgk/debug.c

Modified: trunk/reactos/include/ddk/ntstatus.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ddk/ntstatus.h?rev=24572&r1=24571&r2=24572&view=diff
==============================================================================
--- trunk/reactos/include/ddk/ntstatus.h (original)
+++ trunk/reactos/include/ddk/ntstatus.h Thu Oct 19 11:04:21 2006
@@ -1099,6 +1099,25 @@
 #define STATUS_CLUSTER_NETWORK_NOT_INTERNAL ((NTSTATUS)0xC0130016L)
 #define STATUS_CLUSTER_POISONED ((NTSTATUS)0xC0130017L)
 
+/*
+* Debug codes
+*/
+
+#define DBG_EXCEPTION_HANDLED            ((NTSTATUS)0x00010001)
+#define DBG_CONTINUE                     ((NTSTATUS)0x00010002)
+#define DBG_REPLY_LATER                  ((NTSTATUS)0x40010001)
+#define DBG_UNABLE_TO_PROVIDE_HANDLE     ((NTSTATUS)0x40010002)
+#define DBG_TERMINATE_THREAD             ((NTSTATUS)0x40010003)
+#define DBG_TERMINATE_PROCESS            ((NTSTATUS)0x40010004)
+#define DBG_CONTROL_C                    ((NTSTATUS)0x40010005)
+#define DBG_PRINTEXCEPTION_C             ((NTSTATUS)0x40010006)
+#define DBG_RIPEXCEPTION                 ((NTSTATUS)0x40010007)
+#define DBG_CONTROL_BREAK                ((NTSTATUS)0x40010008)
+#define DBG_COMMAND_EXCEPTION            ((NTSTATUS)0x40010009)
+#define DBG_EXCEPTION_NOT_HANDLED        ((NTSTATUS)0x80010001)
+#define DBG_NO_STATE_CHANGE              ((NTSTATUS)0xC0010001)
+#define DBG_APP_NOT_IDLE                 ((NTSTATUS)0xC0010002)
+
 #ifdef __cplusplus
 }
 #endif

Modified: trunk/reactos/include/ndk/dbgktypes.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/dbgktypes.h?rev=24572&r1=24571&r2=24572&view=diff
==============================================================================
--- trunk/reactos/include/ndk/dbgktypes.h (original)
+++ trunk/reactos/include/ndk/dbgktypes.h Thu Oct 19 11:04:21 2006
@@ -30,6 +30,7 @@
 //
 #define DEBUG_OBJECT_WAIT_STATE_CHANGE      0x0001
 #define DEBUG_OBJECT_ADD_REMOVE_PROCESS     0x0002
+#define DEBUG_OBJECT_SET_INFORMATION        0x0004
 #define DEBUG_OBJECT_ALL_ACCESS             (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x0F)
 
 //
@@ -172,8 +173,8 @@
 typedef struct _DBGKM_MSG
 {
     PORT_MESSAGE h;
-    ULONG Opcode;
-    ULONG Status;
+    ULONG ApiNumber;
+    ULONG ReturnedStatus;
     union
     {
         DBGKM_EXCEPTION Exception;
@@ -186,4 +187,25 @@
     };
 } DBGKM_MSG, *PDBGKM_MSG;
 
+#ifndef NTOS_MODE_USER
+
+//
+// Debug Event
+//
+typedef struct _DEBUG_EVENT
+{
+    LIST_ENTRY EventList;
+    KEVENT ContinueEvent;
+    CLIENT_ID ClientId;
+    PEPROCESS Process;
+    PETHREAD Thread;
+    NTSTATUS Status;
+    ULONG Flags;
+    PETHREAD BackoutThread;
+    DBGKM_MSG ApiMsg;
+} DEBUG_EVENT, *PDEBUG_EVENT;
+
+
 #endif
+
+#endif

Modified: trunk/reactos/ntoskrnl/dbgk/debug.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/dbgk/debug.c?rev=24572&r1=24571&r2=24572&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/dbgk/debug.c (original)
+++ trunk/reactos/ntoskrnl/dbgk/debug.c Thu Oct 19 11:04:21 2006
@@ -7,15 +7,76 @@
  * PROGRAMMERS:     Alex Ionescu (alex at relsoft.net)
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 POBJECT_TYPE DbgkDebugObjectType;
-
-/* FUNCTIONS *****************************************************************/
+KGUARDED_MUTEX DbgkpProcessDebugPortMutex;
+
+GENERIC_MAPPING DbgkDebugObjectMapping =
+{
+    STANDARD_RIGHTS_READ    | DEBUG_OBJECT_WAIT_STATE_CHANGE,
+    STANDARD_RIGHTS_WRITE   | DEBUG_OBJECT_ADD_REMOVE_PROCESS,
+    STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
+    DEBUG_OBJECT_ALL_ACCESS
+};
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+DbgkpDeleteObject(IN PVOID Object)
+{
+    PDBGK_DEBUG_OBJECT DebugObject = Object;
+    PAGED_CODE();
+
+    /* Sanity check */
+    ASSERT(IsListEmpty(&DebugObject->StateEventListEntry));
+}
+
+VOID
+NTAPI
+DbgkpCloseObject(IN PEPROCESS Process OPTIONAL,
+                 IN PVOID ObjectBody,
+                 IN ACCESS_MASK GrantedAccess,
+                 IN ULONG HandleCount,
+                 IN ULONG SystemHandleCount)
+{
+    /* FIXME: Implement */
+    ASSERT(FALSE);
+}
+
+VOID
+INIT_FUNCTION
+NTAPI
+DbgkInitialize(VOID)
+{
+    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+    UNICODE_STRING Name;
+    PAGED_CODE();
+
+    /* Initialize the process debug port mutex */
+    KeInitializeGuardedMutex(&DbgkpProcessDebugPortMutex);
+
+    /* Create the Event Pair Object Type */
+    RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+    RtlInitUnicodeString(&Name, L"DebugObject");
+    ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+    ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DBGK_DEBUG_OBJECT);
+    ObjectTypeInitializer.GenericMapping = DbgkDebugObjectMapping;
+    ObjectTypeInitializer.PoolType = NonPagedPool;
+    ObjectTypeInitializer.ValidAccessMask = DEBUG_OBJECT_WAIT_STATE_CHANGE;
+    ObjectTypeInitializer.UseDefaultObject = TRUE;
+    ObjectTypeInitializer.CloseProcedure = DbgkpCloseObject;
+    ObjectTypeInitializer.DeleteProcedure = DbgkpDeleteObject;
+    ObCreateObjectType(&Name,
+                       &ObjectTypeInitializer,
+                       NULL,
+                       &DbgkDebugObjectType);
+}
 
 VOID
 NTAPI
@@ -35,6 +96,66 @@
     return FALSE;
 }
 
+VOID
+NTAPI
+DbgkpWakeTarget(IN PDEBUG_EVENT DebugEvent)
+{
+    /* FIXME: TODO */
+    return;
+}
+
+NTSTATUS
+NTAPI
+DbgkpPostFakeProcessCreateMessages(IN PEPROCESS Process,
+                                   IN PDBGK_DEBUG_OBJECT DebugObject,
+                                   IN PETHREAD *LastThread)
+{
+    /* FIXME: Implement */
+    *LastThread = NULL;
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+DbgkpSetProcessDebugObject(IN PEPROCESS Process,
+                           IN PDBGK_DEBUG_OBJECT DebugObject,
+                           IN NTSTATUS MsgStatus,
+                           IN PETHREAD LastThread)
+{
+    /* FIXME: TODO */
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+DbgkClearProcessDebugObject(IN PEPROCESS Process,
+                            IN PDBGK_DEBUG_OBJECT SourceDebugObject)
+{
+    /* FIXME: TODO */
+    return STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+DbgkpConvertKernelToUserStateChange(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
+                                    IN PDEBUG_EVENT DebugEvent)
+{
+    /* FIXME: TODO */
+    return;
+}
+
+VOID
+NTAPI
+DbgkpOpenHandles(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
+                 IN PEPROCESS Process,
+                 IN PETHREAD Thread)
+{
+    /* FIXME: TODO */
+    return;
+}
+
+
+/* PUBLIC FUNCTIONS **********************************************************/
 
 NTSTATUS
 NTAPI
@@ -47,25 +168,23 @@
     PDBGK_DEBUG_OBJECT DebugObject;
     HANDLE hDebug;
     NTSTATUS Status = STATUS_SUCCESS;
-
     PAGED_CODE();
-    DPRINT("NtCreateDebugObject(0x%p, 0x%x, 0x%p)\n", DebugHandle, DesiredAccess, ObjectAttributes);
-
-    /* Check Output Safety */
-    if(PreviousMode != KernelMode) {
-
-        _SEH_TRY {
-
-            ProbeForWrite(DebugHandle,
-                          sizeof(HANDLE),
-                          sizeof(ULONG));
-        } _SEH_HANDLE {
-
+
+    /* Check if we were called from user mode*/
+    if (PreviousMode != KernelMode)
+    {
+        /* Enter SEH for probing */
+        _SEH_TRY
+        {
+            /* Probe the handle */
+            ProbeForWrite(DebugHandle, sizeof(HANDLE), sizeof(ULONG));
+        }
+        _SEH_HANDLE
+        {
+            /* Get exception error */
             Status = _SEH_GetExceptionCode();
-
         } _SEH_END;
-
-        if(!NT_SUCCESS(Status)) return Status;
+        if (!NT_SUCCESS(Status)) return Status;
     }
 
     /* Create the Object */
@@ -78,10 +197,8 @@
                             0,
                             0,
                             (PVOID*)&DebugObject);
-
-    /* Check for Success */
-    if(NT_SUCCESS(Status)) {
-
+    if (NT_SUCCESS(Status))
+    {
         /* Initialize the Debug Object's Fast Mutex */
         ExInitializeFastMutex(&DebugObject->Mutex);
 
@@ -104,16 +221,15 @@
         ObDereferenceObject(DebugObject);
 
         /* Check for success and return handle */
-        if(NT_SUCCESS(Status)) {
-
-            _SEH_TRY {
-
+        if (NT_SUCCESS(Status))
+        {
+            _SEH_TRY
+            {
                 *DebugHandle = hDebug;
-
-            } _SEH_HANDLE {
-
+            }
+            _SEH_HANDLE
+            {
                 Status = _SEH_GetExceptionCode();
-
             } _SEH_END;
         }
     }
@@ -124,61 +240,507 @@
 
 NTSTATUS
 NTAPI
-NtWaitForDebugEvent(IN HANDLE DebugObject, // Debug object handle must grant DEBUG_OBJECT_WAIT_STATE_CHANGE access.
-                    IN BOOLEAN Alertable,
-                    IN PLARGE_INTEGER Timeout OPTIONAL,
-                    OUT PDBGUI_WAIT_STATE_CHANGE StateChange)
-{
-
-    UNIMPLEMENTED;
-
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-NtDebugContinue(IN HANDLE DebugObject,    // Debug object handle must grant DEBUG_OBJECT_WAIT_STATE_CHANGE access.
+NtDebugContinue(IN HANDLE DebugHandle,
                 IN PCLIENT_ID AppClientId,
                 IN NTSTATUS ContinueStatus)
 {
-
-    UNIMPLEMENTED;
-
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-NtDebugActiveProcess(IN HANDLE Process,     // Process handle must grant PROCESS_SUSPEND_RESUME access.
-                     IN HANDLE DebugObject)  // Debug object handle must grant DEBUG_OBJECT_ADD_REMOVE_PROCESS access.
-{
-
-    UNIMPLEMENTED;
-
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-NtRemoveProcessDebug(IN HANDLE Process,     // Process handle must grant PROCESS_SUSPEND_RESUME access.
-                     IN HANDLE DebugObject)  // Debug object handle must grant DEBUG_OBJECT_ADD_REMOVE_PROCESS access.
-{
-
-    UNIMPLEMENTED;
-
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-NtSetInformationDebugObject(IN HANDLE DebugObject, // Debug object handle need not grant any particular access right.
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PDBGK_DEBUG_OBJECT DebugObject;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PDEBUG_EVENT DebugEvent = NULL, DebugEventToWake = NULL;
+    PLIST_ENTRY ListHead, NextEntry;
+    BOOLEAN NeedsWake = FALSE;
+    CLIENT_ID ClientId;
+    PAGED_CODE();
+
+    /* Check if we were called from user mode*/
+    if (PreviousMode != KernelMode)
+    {
+        /* Enter SEH for probing */
+        _SEH_TRY
+        {
+            /* Probe the handle */
+            ProbeForRead(AppClientId, sizeof(CLIENT_ID), sizeof(ULONG));
+            ClientId = *AppClientId;
+        }
+        _SEH_HANDLE
+        {
+            /* Get exception error */
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Make sure that the status is valid */
+    if ((ContinueStatus != DBG_EXCEPTION_NOT_HANDLED) &&
+        (ContinueStatus != DBG_REPLY_LATER) &&
+        (ContinueStatus != DBG_UNABLE_TO_PROVIDE_HANDLE) &&
+        (ContinueStatus != DBG_TERMINATE_THREAD) &&
+        (ContinueStatus != DBG_TERMINATE_PROCESS))
+    {
+        /* Invalid status */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+    else
+    {
+        /* Get the debug object */
+        Status = ObReferenceObjectByHandle(DebugHandle,
+                                           DEBUG_OBJECT_WAIT_STATE_CHANGE,
+                                           DbgkDebugObjectType,
+                                           PreviousMode,
+                                           (PVOID*)&DebugObject,
+                                           NULL);
+        if (NT_SUCCESS(Status))
+        {
+            /* Acquire the mutex */
+            ExAcquireFastMutex(&DebugObject->Mutex);
+
+            /* Loop the state list */
+            ListHead = &DebugObject->StateEventListEntry;
+            NextEntry = ListHead->Flink;
+            while (ListHead != NextEntry)
+            {
+                /* Get the current debug event */
+                DebugEvent = CONTAINING_RECORD(NextEntry,
+                                               DEBUG_EVENT,
+                                               EventList);
+
+                /* Compare process ID */
+                if (DebugEvent->ClientId.UniqueProcess ==
+                    ClientId.UniqueProcess)
+                {
+                    /* Check if we already found a match */
+                    if (NeedsWake)
+                    {
+                        /* Wake it up and break out */
+                        DebugEvent->Flags &= ~4;
+                        KeSetEvent(&DebugEvent->ContinueEvent,
+                                   IO_NO_INCREMENT,
+                                   FALSE);
+                        break;
+                    }
+
+                    /* Compare thread ID and flag */
+                    if ((DebugEvent->ClientId.UniqueThread ==
+                        ClientId.UniqueThread) && (DebugEvent->Flags & 1))
+                    {
+                        /* Remove the event from the list */
+                        RemoveEntryList(NextEntry);
+
+                        /* Remember who to wake */
+                        NeedsWake = TRUE;
+                        DebugEventToWake = DebugEvent;
+                    }
+                }
+
+                /* Go to the next entry */
+                NextEntry = NextEntry->Flink;
+            }
+
+            /* Release the mutex */
+            ExReleaseFastMutex(&DebugObject->Mutex);
+
+            /* Dereference the object */
+            ObDereferenceObject(DebugObject);
+
+            /* Check if need a wait */
+            if (NeedsWake)
+            {
+                /* Set the continue status */
+                DebugEvent->ApiMsg.ReturnedStatus = Status;
+                DebugEvent->Status = STATUS_SUCCESS;
+
+                /* Wake the target */
+                DbgkpWakeTarget(DebugEvent);
+            }
+            else
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+            }
+        }
+    }
+
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtDebugActiveProcess(IN HANDLE ProcessHandle,
+                     IN HANDLE DebugHandle)
+{
+    PEPROCESS Process;
+    PDBGK_DEBUG_OBJECT DebugObject;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    PETHREAD LastThread;
+    NTSTATUS Status;
+
+    /* Reference the process */
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       PROCESS_SUSPEND_RESUME,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)&Process,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Don't allow debugging the initial system process */
+    if (Process == PsInitialSystemProcess) return STATUS_ACCESS_DENIED;
+
+    /* Reference the debug object */
+    Status = ObReferenceObjectByHandle(DebugHandle,
+                                       DEBUG_OBJECT_ADD_REMOVE_PROCESS,
+                                       DbgkDebugObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&DebugObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Dereference the process and exit */
+        ObDereferenceObject(Process);
+        return Status;
+    }
+
+    /* Acquire process rundown protection */
+    if (!ExAcquireRundownProtection(&Process->RundownProtect))
+    {
+        /* Dereference the process and debug object and exit */
+        ObDereferenceObject(Process);
+        ObDereferenceObject(DebugObject);
+        return STATUS_PROCESS_IS_TERMINATING;
+    }
+
+    /* Send fake create messages for debuggers to have a consistent state */
+    Status = DbgkpPostFakeProcessCreateMessages(Process,
+                                                DebugObject,
+                                                &LastThread);
+    Status = DbgkpSetProcessDebugObject(Process,
+                                        DebugObject,
+                                        Status,
+                                        LastThread);
+
+    /* Release rundown protection */
+    ExReleaseRundownProtection(&Process->RundownProtect);
+
+    /* Dereference the process and debug object and return status */
+    ObDereferenceObject(Process);
+    ObDereferenceObject(DebugObject);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtRemoveProcessDebug(IN HANDLE ProcessHandle,
+                     IN HANDLE DebugHandle)
+{
+    PEPROCESS Process;
+    PDBGK_DEBUG_OBJECT DebugObject;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    NTSTATUS Status;
+
+    /* Reference the process */
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       PROCESS_SUSPEND_RESUME,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)&Process,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Reference the debug object */
+    Status = ObReferenceObjectByHandle(DebugHandle,
+                                       DEBUG_OBJECT_ADD_REMOVE_PROCESS,
+                                       DbgkDebugObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&DebugObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Dereference the process and exit */
+        ObDereferenceObject(Process);
+        return Status;
+    }
+
+    /* Remove the debug object */
+    Status = DbgkClearProcessDebugObject(Process, DebugObject);
+
+    /* Dereference the process and debug object and return status */
+    ObDereferenceObject(Process);
+    ObDereferenceObject(DebugObject);
+    return Status;
+}
+
+static const INFORMATION_CLASS_INFO DbgkpDebugObjectInfoClass[] =
+{
+    /* DebugObjectUnusedInformation */
+    ICI_SQ_SAME(sizeof(ULONG), sizeof(ULONG), 0),
+    /* DebugObjectKillProcessOnExitInformation */
+    ICI_SQ_SAME(sizeof(DEBUG_OBJECT_KILL_PROCESS_ON_EXIT_INFORMATION), sizeof(ULONG), ICIF_SET),
+};
+
+NTSTATUS
+NTAPI
+NtSetInformationDebugObject(IN HANDLE DebugHandle,
                             IN DEBUGOBJECTINFOCLASS DebugObjectInformationClass,
                             IN PVOID DebugInformation,
                             IN ULONG DebugInformationLength,
                             OUT PULONG ReturnLength OPTIONAL)
 {
-    UNIMPLEMENTED;
-
-    return STATUS_NOT_IMPLEMENTED;
-}
+    PDBGK_DEBUG_OBJECT DebugObject;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PDEBUG_OBJECT_KILL_PROCESS_ON_EXIT_INFORMATION DebugInfo = DebugInformation;
+    PAGED_CODE();
+
+    /* Check buffers and parameters */
+    Status = DefaultSetInfoBufferCheck(DebugObjectInformationClass,
+                                       DbgkpDebugObjectInfoClass,
+                                       sizeof(DbgkpDebugObjectInfoClass) /
+                                       sizeof(DbgkpDebugObjectInfoClass[0]),
+                                       DebugInformation,
+                                       DebugInformationLength,
+                                       PreviousMode);
+
+    /* Return required length to user-mode */
+    if (ReturnLength) *ReturnLength = sizeof(*DebugInfo);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Open the Object */
+    Status = ObReferenceObjectByHandle(DebugHandle,
+                                       DEBUG_OBJECT_WAIT_STATE_CHANGE,
+                                       DbgkDebugObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&DebugObject,
+                                       NULL);
+    if (NT_SUCCESS(Status))
+    {
+        /* Acquire the object */
+        ExAcquireFastMutex(&DebugObject->Mutex);
+
+        /* Set the proper flag */
+        if (DebugInfo->KillProcessOnExit)
+        {
+            /* Enable killing the process */
+            DebugObject->Flags |= 2;
+        }
+        else
+        {
+            /* Disable */
+            DebugObject->Flags &= ~2;
+        }
+
+        /* Release the mutex */
+        ExReleaseFastMutex(&DebugObject->Mutex);
+
+        /* Release the Object */
+        ObDereferenceObject(DebugObject);
+    }
+
+    /* Return Status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtWaitForDebugEvent(IN HANDLE DebugHandle,
+                    IN BOOLEAN Alertable,
+                    IN PLARGE_INTEGER Timeout OPTIONAL,
+                    OUT PDBGUI_WAIT_STATE_CHANGE StateChange)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    LARGE_INTEGER SafeTimeOut;
+    PEPROCESS Process;
+    LARGE_INTEGER StartTime;
+    PETHREAD Thread;
+    BOOLEAN GotEvent;
+    LARGE_INTEGER NewTime;
+    PDBGK_DEBUG_OBJECT DebugObject;
+    DBGUI_WAIT_STATE_CHANGE WaitStateChange;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PDEBUG_EVENT DebugEvent, DebugEvent2;
+    PLIST_ENTRY ListHead, NextEntry;
+
+    /* Clear the initial wait state change structure */
+    RtlZeroMemory(&WaitStateChange, sizeof(WaitStateChange));
+
+    /* Check if we came with a timeout from user mode */
+    if ((Timeout) && (PreviousMode != KernelMode))
+    {
+        _SEH_TRY
+        {
+            /* Make a copy on the stack */
+            SafeTimeOut = ProbeForReadLargeInteger(Timeout);
+            Timeout = &SafeTimeOut;
+        }
+        _SEH_HANDLE
+        {
+            /* Get the exception code */
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+        if (!NT_SUCCESS(Status)) return Status;
+
+        /* Query the current time */
+        KeQuerySystemTime(&StartTime);
+    }
+
+    /* Check if the call is from user mode */
+    if (PreviousMode == UserMode)
+    {
+        /* FIXME: Probe the state change structure */
+    }
+
+    /* Get the debug object */
+    Status = ObReferenceObjectByHandle(DebugHandle,
+                                       DEBUG_OBJECT_WAIT_STATE_CHANGE,
+                                       DbgkDebugObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&DebugObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Clear process and thread */
+    Process = NULL;
+    Thread = NULL;
+
+    /* Wait on the debug object given to us */
+    Status = KeWaitForSingleObject(DebugObject,
+                                   Executive,
+                                   PreviousMode,
+                                   Alertable,
+                                   Timeout);
+
+    /* Start the wait loop */
+    while (TRUE)
+    {
+        if (!NT_SUCCESS(Status) ||
+            (Status == STATUS_TIMEOUT) ||
+            (Status == STATUS_ALERTED) ||
+            (Status == STATUS_USER_APC))
+        {
+            /* Break out the wait */
+            break;
+        }
+
+        /* Lock the object */
+        GotEvent = FALSE;
+        ExAcquireFastMutex(&DebugObject->Mutex);
+
+        /* Check if a debugger is connected */
+        if (DebugObject->Flags & 1)
+        {
+            /* Not connected */
+            Status = STATUS_DEBUGGER_INACTIVE;
+        }
+        else
+        {
+            /* Loop the events */
+            ListHead = &DebugObject->StateEventListEntry;
+            NextEntry =  ListHead->Flink;
+            while (ListHead != NextEntry)
+            {
+                /* Get the debug event */
+                DebugEvent = CONTAINING_RECORD(NextEntry,
+                                               DEBUG_EVENT,
+                                               EventList);
+
+                /* Check flags */
+                if (!(DebugEvent->Flags & (4 | 1)))
+                {
+                    /* We got an event */
+                    GotEvent = TRUE;
+
+                    /* Loop the list internally */
+                    while (&DebugEvent->EventList != NextEntry)
+                    {
+                        /* Get the debug event */
+                        DebugEvent2 = CONTAINING_RECORD(NextEntry,
+                                                        DEBUG_EVENT,
+                                                        EventList);
+
+                        /* Try to match process IDs */
+                        if (DebugEvent2->ClientId.UniqueProcess ==
+                            DebugEvent->ClientId.UniqueProcess)
+                        {
+                            /* Found it, break out */
+                            DebugEvent->Flags |= 4;
+                            DebugEvent->BackoutThread = NULL;
+                            GotEvent = FALSE;
+                            break;
+                        }
+
+                        /* Move to the next entry */
+                        NextEntry = NextEntry->Flink;
+                    }
+
+                    /* Check if we still have a valid event */
+                    if (GotEvent) break;
+                }
+
+                /* Move to the next entry */
+                NextEntry = NextEntry->Flink;
+            }
+
+            /* Check if we have an event */
+            if (GotEvent)
+            {
+                /* Save and reference the process and thread */
+                Process = DebugEvent->Process;
+                Thread = DebugEvent->Thread;
+                ObReferenceObject(Process);
+                ObReferenceObject(Thread);
+
+                /* Convert to user-mode structure */
+                DbgkpConvertKernelToUserStateChange(&WaitStateChange,
+                                                    DebugEvent);
+
+                /* Set flag */
+                DebugEvent->Flags |= 1;
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                /* Unsignal the event */
+                DebugObject->Event.Header.SignalState = 0;
+                Status = STATUS_SUCCESS;
+            }
+        }
+
+        /* Release the mutex */
+        ExReleaseFastMutex(&DebugObject->Mutex);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Check if we got an event */
+        if (GotEvent)
+        {
+            /* Check if we can wait again */
+            if (!SafeTimeOut.QuadPart)
+            {
+                /* Query the new time */
+                KeQuerySystemTime(&NewTime);
+
+                /* Substract times */
+                /* FIXME: TODO */
+            }
+        }
+        else
+        {
+            /* Open the handles and dereference the objects */
+            DbgkpOpenHandles(&WaitStateChange, Process, Thread);
+            ObDereferenceObject(Process);
+            ObDereferenceObject(Thread);
+        }
+    }
+
+    /* We're, dereference the object */
+    ObDereferenceObject(DebugObject);
+
+    /* Return our wait state change structure */
+    RtlMoveMemory(StateChange,
+                  &WaitStateChange,
+                  sizeof(DBGUI_WAIT_STATE_CHANGE));
+    return Status;
+}
+
 /* EOF */




More information about the Ros-diffs mailing list