- DebugSetProcessKillOnExit: Use SetLastErrorByStatus for NTSTATUS codes
[reactos.git] / reactos / dll / win32 / kernel32 / debug / debugger.c
index 4a9688b..3685539 100644 (file)
 /* INCLUDES *****************************************************************/
 
 #include <k32.h>
-
 #define NDEBUG
-#include "debug.h"
+#include <debug.h>
+
+typedef struct _DBGSS_THREAD_DATA
+{
+    struct _DBGSS_THREAD_DATA *Next;
+    HANDLE ThreadHandle;
+    HANDLE ProcessHandle;
+    DWORD ProcessId;
+    DWORD ThreadId;
+    BOOLEAN HandleMarked;
+} DBGSS_THREAD_DATA, *PDBGSS_THREAD_DATA;
+
+#define DbgSsSetThreadData(d) \
+    NtCurrentTeb()->DbgSsReserved[0] = d
+
+#define DbgSsGetThreadData() \
+    ((PDBGSS_THREAD_DATA)NtCurrentTeb()->DbgSsReserved[0])
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+WINAPI
+SaveThreadHandle(IN DWORD dwProcessId,
+                 IN DWORD dwThreadId,
+                 IN HANDLE hThread)
+{
+    PDBGSS_THREAD_DATA ThreadData;
+
+    /* Allocate a thread structure */
+    ThreadData = RtlAllocateHeap(RtlGetProcessHeap(),
+                                 0,
+                                 sizeof(DBGSS_THREAD_DATA));
+    if (!ThreadData) return;
+
+    /* Fill it out */
+    ThreadData->ThreadHandle = hThread;
+    ThreadData->ProcessId = dwProcessId;
+    ThreadData->ThreadId = dwThreadId;
+    ThreadData->ProcessHandle = NULL;
+    ThreadData->HandleMarked = FALSE;
+
+    /* Link it */
+    ThreadData->Next = DbgSsGetThreadData();
+    DbgSsSetThreadData(ThreadData);
+}
+
+VOID
+WINAPI
+SaveProcessHandle(IN DWORD dwProcessId,
+                  IN HANDLE hProcess)
+{
+    PDBGSS_THREAD_DATA ThreadData;
+
+    /* Allocate a thread structure */
+    ThreadData = RtlAllocateHeap(RtlGetProcessHeap(),
+                                 0,
+                                 sizeof(DBGSS_THREAD_DATA));
+    if (!ThreadData) return;
+
+    /* Fill it out */
+    ThreadData->ProcessHandle = hProcess;
+    ThreadData->ProcessId = dwProcessId;
+    ThreadData->ThreadId = 0;
+    ThreadData->ThreadHandle = NULL;
+    ThreadData->HandleMarked = FALSE;
+
+    /* Link it */
+    ThreadData->Next = DbgSsGetThreadData();
+    DbgSsSetThreadData(ThreadData);
+}
+
+VOID
+WINAPI
+MarkThreadHandle(IN DWORD dwThreadId)
+{
+    PDBGSS_THREAD_DATA ThreadData;
+
+    /* Loop all thread data events */
+    ThreadData = DbgSsGetThreadData();
+    while (ThreadData)
+    {
+        /* Check if this one matches */
+        if (ThreadData->ThreadId == dwThreadId)
+        {
+            /* Mark the structure and break out */
+            ThreadData->HandleMarked = TRUE;
+            break;
+        }
+
+        /* Move to the next one */
+        ThreadData = ThreadData->Next;
+    }
+}
+
+VOID
+WINAPI
+MarkProcessHandle(IN DWORD dwProcessId)
+{
+    PDBGSS_THREAD_DATA ThreadData;
+
+    /* Loop all thread data events */
+    ThreadData = DbgSsGetThreadData();
+    while (ThreadData)
+    {
+        /* Check if this one matches */
+        if (ThreadData->ProcessId == dwProcessId)
+        {
+            /* Make sure the thread ID is empty */
+            if (!ThreadData->ThreadId)
+            {
+                /* Mark the structure and break out */
+                ThreadData->HandleMarked = TRUE;
+                break;
+            }
+        }
+
+        /* Move to the next one */
+        ThreadData = ThreadData->Next;
+    }
+}
+
+VOID
+WINAPI
+RemoveHandles(IN DWORD dwProcessId,
+              IN DWORD dwThreadId)
+{
+    PDBGSS_THREAD_DATA ThreadData;
+
+    /* Loop all thread data events */
+    ThreadData = DbgSsGetThreadData();
+    while (ThreadData)
+    {
+        /* Check if this one matches */
+        if (ThreadData->ProcessId == dwProcessId)
+        {
+            /* Make sure the thread ID matches too */
+            if (ThreadData->ThreadId == dwThreadId)
+            {
+                /* Check if we have a thread handle */
+                if (ThreadData->ThreadHandle)
+                {
+                    /* Close it */
+                    CloseHandle(ThreadData->ThreadHandle);
+                }
+
+                /* Check if we have a process handle */
+                if (ThreadData->ProcessHandle)
+                {
+                    /* Close it */
+                    CloseHandle(ThreadData->ProcessHandle);
+                }
+
+                /* Unlink the thread data */
+                DbgSsSetThreadData(ThreadData->Next);
+
+                /* Free it*/
+                RtlFreeHeap(RtlGetProcessHeap(), 0, ThreadData);
+
+                /* Move to the next structure */
+                ThreadData = DbgSsGetThreadData();
+                continue;
+            }
+        }
+
+        /* Move to the next one */
+        ThreadData = ThreadData->Next;
+    }
+}
+
+VOID
+WINAPI
+CloseAllProcessHandles(IN DWORD dwProcessId)
+{
+    PDBGSS_THREAD_DATA ThreadData;
+
+    /* Loop all thread data events */
+    ThreadData = DbgSsGetThreadData();
+    while (ThreadData)
+    {
+        /* Check if this one matches */
+        if (ThreadData->ProcessId == dwProcessId)
+        {
+            /* Check if we have a thread handle */
+            if (ThreadData->ThreadHandle)
+            {
+                /* Close it */
+                CloseHandle(ThreadData->ThreadHandle);
+            }
+
+            /* Check if we have a process handle */
+            if (ThreadData->ProcessHandle)
+            {
+                /* Close it */
+                CloseHandle(ThreadData->ProcessHandle);
+            }
+
+            /* Unlink the thread data */
+            DbgSsSetThreadData(ThreadData->Next);
+
+            /* Free it*/
+            RtlFreeHeap(RtlGetProcessHeap(), 0, ThreadData);
+
+            /* Move to the next structure */
+            ThreadData = DbgSsGetThreadData();
+            continue;
+        }
+
+        /* Move to the next one */
+        ThreadData = ThreadData->Next;
+    }
+}
+
+HANDLE
+WINAPI
+ProcessIdToHandle(IN DWORD dwProcessId)
+{
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE Handle;
+    CLIENT_ID ClientId;
+
+    /* If we don't have a PID, look it up */
+    if (dwProcessId == -1U) dwProcessId = (DWORD)CsrGetProcessId();
+
+    /* Open a handle to the process */
+    ClientId.UniqueThread = NULL;
+    ClientId.UniqueProcess = (HANDLE)dwProcessId;
+    InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+    Status = NtOpenProcess(&Handle,
+                           PROCESS_ALL_ACCESS,
+                           &ObjectAttributes,
+                           &ClientId);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Fail */
+        SetLastErrorByStatus(Status);
+        return 0;
+    }
 
-/* FUNCTIONS *****************************************************************/
+    /* Return the handle */
+    return Handle;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
 
 /*
  * @implemented
@@ -77,37 +317,11 @@ ContinueDebugEvent(IN DWORD dwProcessId,
         return FALSE;
     }
 
-    /* Succes */
-    return TRUE;
-}
-
-HANDLE
-ProcessIdToHandle(IN DWORD dwProcessId)
-{
-    NTSTATUS Status;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    HANDLE Handle;
-    CLIENT_ID ClientId;
-
-    /* If we don't have a PID, look it up */
-    if (dwProcessId == 0xFFFFFFFF) dwProcessId = (DWORD)CsrGetProcessId();
-
-    /* Open a handle to the process */
-    ClientId.UniqueProcess = (HANDLE)dwProcessId;
-    InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
-    Status = NtOpenProcess(&Handle,
-                           PROCESS_ALL_ACCESS,
-                           &ObjectAttributes,
-                           &ClientId);
-    if (!NT_SUCCESS(Status))
-    {
-        /* Fail */
-        SetLastErrorByStatus(Status);
-        return 0;
-    }
+    /* Remove the process/thread handles */
+    RemoveHandles(dwProcessId, dwThreadId);
 
-    /* Return the handle */
-    return Handle;
+    /* Success */
+    return TRUE;
 }
 
 /*
@@ -134,6 +348,9 @@ DebugActiveProcess(IN DWORD dwProcessId)
 
     /* Now debug the process */
     Status = DbgUiDebugActiveProcess(Handle);
+    NtClose(Handle);
+
+    /* Check if debugging worked */
     if (!NT_SUCCESS(Status))
     {
         /* Fail */
@@ -159,6 +376,9 @@ DebugActiveProcessStop(IN DWORD dwProcessId)
     Handle = ProcessIdToHandle(dwProcessId);
     if (!Handle) return FALSE;
 
+    /* Close all the process handles */
+    CloseAllProcessHandles(dwProcessId);
+
     /* Now stop debgging the process */
     Status = DbgUiStopDebugging(Handle);
     NtClose(Handle);
@@ -227,7 +447,7 @@ DebugSetProcessKillOnExit(IN BOOL KillOnExit)
     if (!NT_SUCCESS(Status))
     {
         /* Fail */
-        SetLastError(Status);
+        SetLastErrorByStatus(Status);
         return FALSE;
     }
 
@@ -240,22 +460,115 @@ DebugSetProcessKillOnExit(IN BOOL KillOnExit)
  */
 BOOL
 WINAPI
-IsDebuggerPresent (VOID)
+IsDebuggerPresent(VOID)
 {
     return (BOOL)NtCurrentPeb()->BeingDebugged;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 WINAPI
 WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent,
-                  DWORD dwMilliseconds)
+                  IN DWORD dwMilliseconds)
 {
-    /* FIXME: TODO */
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    LARGE_INTEGER WaitTime;
+    PLARGE_INTEGER Timeout;
+    DBGUI_WAIT_STATE_CHANGE WaitStateChange;
+    NTSTATUS Status;
+
+    /* Check if this is an infinite wait */
+    if (dwMilliseconds == INFINITE)
+    {
+        /* Under NT, this means no timer argument */
+        Timeout = NULL;
+    }
+    else
+    {
+        /* Otherwise, convert the time to NT Format */
+        WaitTime.QuadPart = UInt32x32To64(-10000, dwMilliseconds);
+        Timeout = &WaitTime;
+    }
+
+    /* Loop while we keep getting interrupted */
+    do
+    {
+        /* Call the native API */
+        Status = DbgUiWaitStateChange(&WaitStateChange, Timeout);
+    } while ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC));
+
+    /* Check if the wait failed */
+    if (!(NT_SUCCESS(Status)) || (Status == DBG_UNABLE_TO_PROVIDE_HANDLE))
+    {
+        /* Set the error code and quit */
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+
+    /* Check if we timed out */
+    if (Status == STATUS_TIMEOUT)
+    {
+        /* Fail with a timeout error */
+        SetLastError(ERROR_SEM_TIMEOUT);
+        return FALSE;
+    }
+
+    /* Convert the structure */
+    Status = DbgUiConvertStateChangeStructure(&WaitStateChange, lpDebugEvent);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Set the error code and quit */
+        SetLastErrorByStatus(Status);
+        return FALSE;
+    }
+
+    /* Check what kind of event this was */
+    switch (lpDebugEvent->dwDebugEventCode)
+    {
+        /* New thread was created */
+        case CREATE_THREAD_DEBUG_EVENT:
+
+            /* Setup the thread data */
+            SaveThreadHandle(lpDebugEvent->dwProcessId,
+                             lpDebugEvent->dwThreadId,
+                             lpDebugEvent->u.CreateThread.hThread);
+            break;
+
+        /* New process was created */
+        case CREATE_PROCESS_DEBUG_EVENT:
+
+            /* Setup the process data */
+            SaveProcessHandle(lpDebugEvent->dwProcessId,
+                              lpDebugEvent->u.CreateProcessInfo.hProcess);
+
+            /* Setup the thread data */
+            SaveThreadHandle(lpDebugEvent->dwProcessId,
+                             lpDebugEvent->dwThreadId,
+                             lpDebugEvent->u.CreateThread.hThread);
+            break;
+
+        /* Process was exited */
+        case EXIT_PROCESS_DEBUG_EVENT:
+
+            /* Mark the thread data as such */
+            MarkProcessHandle(lpDebugEvent->dwProcessId);
+            break;
+
+        /* Thread was exited */
+        case EXIT_THREAD_DEBUG_EVENT:
+
+            /* Mark the thread data */
+            MarkThreadHandle(lpDebugEvent->dwThreadId);
+            break;
+
+        /* Nothing to do for anything else */
+        default:
+            break;
+    }
+
+    /* Return success */
+    return TRUE;
 }
 
 /* EOF */