[KDGDB]
authorJérôme Gardou <jerome.gardou@reactos.org>
Mon, 15 Sep 2014 22:05:21 +0000 (22:05 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Mon, 15 Sep 2014 22:05:21 +0000 (22:05 +0000)
 - As pid and tid 0 have a special meaning in GDB, use off-by-one thread and process ID when communicating with it
 - Properly read registers and memory from foreign thread and processes. (This time it was tested and proved to work reliably. __writecr3 ftw!)
 - Loop the list of processes and threads when trying to find them from ID, as PsLookupProessByThreadId and friends can't be used since we can be at any IRQL.
 - Add a few more debug prints to help diagnosing problems.
CORE-8531

svn path=/trunk/; revision=64166

reactos/drivers/base/kdgdb/CMakeLists.txt
reactos/drivers/base/kdgdb/gdb_input.c
reactos/drivers/base/kdgdb/gdb_send.c
reactos/drivers/base/kdgdb/i386_sup.c
reactos/drivers/base/kdgdb/kdgdb.h
reactos/drivers/base/kdgdb/kdpacket.c
reactos/drivers/base/kdgdb/utils.c [new file with mode: 0644]

index cf180c1..bb9236c 100644 (file)
@@ -7,6 +7,7 @@ list(APPEND SOURCE
        gdb_send.c
     kdcom.c
     kdpacket.c
+    utils.c
     kdgdb.h)
 
 # TODO: AMD64, ARM...
index b858a38..115d680 100644 (file)
@@ -7,24 +7,20 @@
 
 #include "kdgdb.h"
 
-#include <pstypes.h>
-
 /* LOCALS *********************************************************************/
-static HANDLE gdb_run_thread;
-/* We might have to attach to a process to read its memory */
-static PEPROCESS AttachedProcess = NULL;
+static ULONG_PTR gdb_run_tid;
 /* Keep track of where we are for qfThreadInfo/qsThreadInfo */
 static LIST_ENTRY* CurrentProcessEntry;
 static LIST_ENTRY* CurrentThreadEntry;
 
 /* GLOBALS ********************************************************************/
-HANDLE gdb_dbg_process;
-HANDLE gdb_dbg_thread;
+UINT_PTR gdb_dbg_pid;
+UINT_PTR gdb_dbg_tid;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 static
-HANDLE
-hex_to_thread(char* buffer)
+UINT_PTR
+hex_to_tid(char* buffer)
 {
     ULONG_PTR ret = 0;
     char hex;
@@ -32,12 +28,13 @@ hex_to_thread(char* buffer)
     {
         hex = hex_value(*buffer++);
         if (hex < 0)
-            return (HANDLE)ret;
+            return ret;
         ret <<= 4;
         ret += hex;
     }
-    return (HANDLE)ret;
+    return ret;
 }
+#define hex_to_pid hex_to_tid
 
 static
 ULONG64
@@ -65,26 +62,26 @@ handle_gdb_set_thread(void)
     {
     case 'c':
         if (strcmp(&gdb_input[2], "-1") == 0)
-            gdb_run_thread = (HANDLE)-1;
+            gdb_run_tid = (ULONG_PTR)-1;
         else
-            gdb_run_thread = hex_to_thread(&gdb_input[2]);
+            gdb_run_tid = hex_to_tid(&gdb_input[2]);
         send_gdb_packet("OK");
         break;
     case 'g':
         KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
         if (strncmp(&gdb_input[2], "p-1", 3) == 0)
         {
-            gdb_dbg_process = (HANDLE)-1;
-            gdb_dbg_thread = (HANDLE)-1;
+            gdb_dbg_pid = (UINT_PTR)-1;
+            gdb_dbg_tid = (UINT_PTR)-1;
         }
         else
         {
             char* ptr = strstr(gdb_input, ".") + 1;
-            gdb_dbg_process = hex_to_thread(&gdb_input[3]);
+            gdb_dbg_pid = hex_to_pid(&gdb_input[3]);
             if (strncmp(ptr, "-1", 2) == 0)
-                gdb_dbg_thread = (HANDLE)-1;
+                gdb_dbg_tid = (UINT_PTR)-1;
             else
-                gdb_dbg_thread = hex_to_thread(ptr);
+                gdb_dbg_tid = hex_to_tid(ptr);
         }
         send_gdb_packet("OK");
         break;
@@ -112,26 +109,22 @@ static
 void
 handle_gdb_thread_alive(void)
 {
-    char* ptr = strstr(gdb_input, ".") + 1;
-    CLIENT_ID ClientId;
+    ULONG_PTR Pid, Tid;
     PETHREAD Thread;
-    NTSTATUS Status;
 
-    ClientId.UniqueProcess = hex_to_thread(&gdb_input[2]);
-    ClientId.UniqueThread = hex_to_thread(ptr);
+    Pid = hex_to_pid(&gdb_input[2]);
+    Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
 
-    Status = PsLookupProcessThreadByCid(&ClientId, NULL, &Thread);
+    /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
+     * So loop. */
+    KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid);
 
-    if (!NT_SUCCESS(Status))
-    {
-        /* Thread doesn't exist */
-        send_gdb_packet("E03");
-        return;
-    }
+    Thread = find_thread(Pid, Tid);
 
-    /* It's OK */
-    ObDereferenceObject(Thread);
-    send_gdb_packet("OK");
+    if (Thread != NULL)
+        send_gdb_packet("OK");
+    else
+        send_gdb_packet("E03");
 }
 
 /* q* packets */
@@ -165,9 +158,9 @@ handle_gdb_query(
     if (strcmp(gdb_input, "qC") == 0)
     {
         char gdb_out[64];
-        sprintf(gdb_out, "QC:p%p.%p;",
-            PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
-            PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
+        sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";",
+            handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)),
+            handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
         send_gdb_packet(gdb_out);
         return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
     }
@@ -175,44 +168,35 @@ handle_gdb_query(
     if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
             || (strncmp(gdb_input, "qsThreadInfo", 12) == 0))
     {
-        LIST_ENTRY* ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
         BOOLEAN FirstThread = TRUE;
         PEPROCESS Process;
         PETHREAD Thread;
         char gdb_out[1024];
-        char* ptr;
+        char* ptr = gdb_out;
         BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0;
 
-        /* Maybe this was not initialized yet */
-        if (!ProcessListHead->Flink)
+        if (Resuming)
         {
-            char gdb_out[64];
-
-            if (Resuming)
+            if (CurrentProcessEntry == (LIST_ENTRY*)1)
             {
-                /* there is only one thread to tell about */
+                /* We're done */
                 send_gdb_packet("l");
+                CurrentProcessEntry = NULL;
                 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
             }
-            /* Just tell GDB about the current thread */
-            sprintf(gdb_out, "mp%p.%p", PsGetCurrentProcessId(), PsGetCurrentThreadId());
-            send_gdb_packet(gdb_out);
-            /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
-            return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
-        }
 
-        if (Resuming)
-        {
             if (CurrentThreadEntry == NULL)
                 CurrentProcessEntry = CurrentProcessEntry->Flink;
         }
         else
             CurrentProcessEntry = ProcessListHead->Flink;
 
-        if (CurrentProcessEntry == ProcessListHead)
+        if ((CurrentProcessEntry == ProcessListHead) ||
+                (CurrentProcessEntry == NULL)) /* Ps is not initialized */
         {
-            /* We're done */
-            send_gdb_packet("l");
+            /* We're almost done. Tell GDB about the idle thread */
+            send_gdb_packet("mp1.1");
+            CurrentProcessEntry = (LIST_ENTRY*)1;
             return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
         }
 
@@ -244,7 +228,9 @@ handle_gdb_query(
             }
 
             ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
-                "p%p.%p", PsGetProcessId(Process), PsGetThreadId(Thread));
+                "p%p.%p",
+                handle_to_gdb_pid(Process->UniqueProcessId),
+                handle_to_gdb_tid(Thread->Cid.UniqueThread));
             if (ptr > (gdb_out + 1024))
             {
                 /* send what we got */
@@ -319,11 +305,10 @@ ReadMemorySendHandler(
     KdpSendPacketHandler = NULL;
     KdpManipulateStateHandler = NULL;
 
-    /* Detach if we have to */
-    if (AttachedProcess != NULL)
+    /* Reset the TLB */
+    if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
     {
-        KeDetachProcess();
-        AttachedProcess = NULL;
+        __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
     }
 }
 
@@ -343,17 +328,17 @@ handle_gdb_read_mem(
         MessageData->Length = 0;
     *MessageLength = 0;
 
-    /* Attach to the debug process to read its memory */
-    if (gdb_dbg_process != PsGetCurrentProcessId())
+    /* Set the TLB according to the process being read. Pid 0 means any process. */
+    if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
     {
-        NTSTATUS Status = PsLookupProcessByProcessId(gdb_dbg_process, &AttachedProcess);
-        if (!NT_SUCCESS(Status))
+        PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
+        if (AttachedProcess == NULL)
         {
             KDDBGPRINT("The current GDB debug thread is invalid!");
             send_gdb_packet("E03");
             return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
         }
-        KeAttachProcess(&AttachedProcess->Pcb);
+        __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
     }
 
     State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
index 87aeca1..dfbc7b6 100644 (file)
@@ -168,15 +168,22 @@ gdb_send_exception(void)
 {
     char gdb_out[1024];
     char* ptr = gdb_out;
-    DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception;
+    PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread;
 
     /* Report to GDB */
     *ptr++ = 'T';
 
-    ptr = exception_code_to_gdb(Exception->ExceptionRecord.ExceptionCode, ptr);
-    ptr += sprintf(ptr, "thread:p%p.%p;",
-        PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
-        PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
+    if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
+    {
+        EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord;
+        ptr = exception_code_to_gdb(ExceptionRecord->ExceptionCode, ptr);
+    }
+    else
+        ptr += sprintf(ptr, "05");
+
+    ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";",
+        handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
+        handle_to_gdb_tid(PsGetThreadId(Thread)));
     ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
     send_gdb_packet(gdb_out);
 }
index dc752b5..7cab7fe 100644 (file)
@@ -7,8 +7,6 @@
 
 #include "kdgdb.h"
 
-#include <pstypes.h>
-
 enum reg_name
 {
     EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
@@ -85,36 +83,62 @@ static
 void*
 thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
 {
-    PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
-
-    /* See if the thread was actually scheduled */
-    if (TrapFrame == NULL)
+    /* See if the guy got a stack */
+    if (Thread->Tcb.InitialStack == NULL)
     {
-        return NULL;
+        static const void* NullValue = NULL;
+        /* Terminated thread ? */
+        switch (reg_name)
+        {
+            case ESP:
+            case EBP:
+            case EIP:
+                *size = 4;
+                return &NullValue;
+            default:
+                return NULL;
+        }
     }
+    else if (Thread->Tcb.TrapFrame)
+    {
+        PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
 
-    *size = 4;
-    switch (reg_name)
+        *size = 4;
+        switch (reg_name)
+        {
+            case EAX: return &TrapFrame->Eax;
+            case ECX: return &TrapFrame->Ecx;
+            case EDX: return &TrapFrame->Edx;
+            case EBX: return &TrapFrame->Ebx;
+            case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ?
+                    &TrapFrame->TempEsp : &TrapFrame->HardwareEsp;
+            case EBP: return &TrapFrame->Ebp;
+            case ESI: return &TrapFrame->Esi;
+            case EDI: return &TrapFrame->Edi;
+            case EIP: return &TrapFrame->Eip;
+            case EFLAGS: return &TrapFrame->EFlags;
+            case CS: return &TrapFrame->SegCs;
+            case SS: return &TrapFrame->HardwareSegSs;
+            case DS: return &TrapFrame->SegDs;
+            case ES: return &TrapFrame->SegEs;
+            case FS: return &TrapFrame->SegFs;
+            case GS: return &TrapFrame->SegGs;
+            default:
+                KDDBGPRINT("Unhandled regname: %d.\n", reg_name);
+        }
+    }
+    else
     {
-        case EAX: return &TrapFrame->Eax;
-        case ECX: return &TrapFrame->Ecx;
-        case EDX: return &TrapFrame->Edx;
-        case EBX: return &TrapFrame->Ebx;
-        case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ?
-                &TrapFrame->TempEsp : &TrapFrame->HardwareEsp;
-        case EBP: return &TrapFrame->Ebp;
-        case ESI: return &TrapFrame->Esi;
-        case EDI: return &TrapFrame->Edi;
-        case EIP: return &TrapFrame->Eip;
-        case EFLAGS: return &TrapFrame->EFlags;
-        case CS: return &TrapFrame->SegCs;
-        case SS: return &TrapFrame->HardwareSegSs;
-        case DS: return &TrapFrame->SegDs;
-        case ES: return &TrapFrame->SegEs;
-        case FS: return &TrapFrame->SegFs;
-        case GS: return &TrapFrame->SegGs;
-        default:
-            KDDBGPRINT("Unhandled regname: %d.\n", reg_name);
+        /* The thread was not yet scheduled */
+        *size = 4;
+        switch(reg_name)
+        {
+            case ESP: return &Thread->Tcb.KernelStack;
+            case EBP: return &((ULONG*)Thread->Tcb.KernelStack)[4];
+            case EIP: return &Thread->StartAddress;
+            default:
+                return NULL;
+        }
     }
     return NULL;
 }
@@ -132,7 +156,10 @@ gdb_send_registers(
     unsigned short size;
     CHAR* ptr = Registers;
 
-    if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
+    KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
+    KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
+    if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
+            gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
     {
         for(i=0; i < 16; i++)
         {
@@ -150,10 +177,10 @@ gdb_send_registers(
     else
     {
         PETHREAD DbgThread;
-        NTSTATUS Status;
 
-        Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread);
-        if (!NT_SUCCESS(Status))
+        DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
+
+        if (DbgThread == NULL)
         {
             /* Thread is dead */
             send_gdb_packet("E03");
@@ -199,7 +226,8 @@ gdb_send_register(
     /* Get the GDB register name (gdb_input = "pXX") */
     reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
 
-    if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
+    if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
+            gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
     {
         /* We can get it from the context of the current exception */
         ptr = ctx_to_reg(&CurrentContext, reg_name, &size);
@@ -207,10 +235,10 @@ gdb_send_register(
     else
     {
         PETHREAD DbgThread;
-        NTSTATUS Status;
 
-        Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread);
-        if (!NT_SUCCESS(Status))
+        DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
+
+        if (DbgThread == NULL)
         {
             /* Thread is dead */
             send_gdb_packet("E03");
index 71f788d..24838e7 100644 (file)
 #include <halfuncs.h>
 #include <stdio.h>
 #include <arc/arc.h>
+#include <inttypes.h>
 #include <windbgkd.h>
 #include <kddll.h>
 
+#include <pstypes.h>
+
 #define KDDEBUG /* uncomment to enable debugging this dll */
 
 #ifndef KDDEBUG
@@ -25,6 +28,18 @@ extern ULONG KdpDbgPrint(const char* Format, ...);
 #define KDDBGPRINT KdpDbgPrint
 #endif
 
+/* GDB doesn't like pid - tid 0, so +1 them */
+FORCEINLINE HANDLE gdb_tid_to_handle(UINT_PTR Tid)
+{
+    return (HANDLE)(Tid - 1);
+}
+#define gdb_pid_to_handle gdb_tid_to_handle
+FORCEINLINE UINT_PTR handle_to_gdb_tid(HANDLE Handle)
+{
+    return (UINT_PTR)Handle + 1;
+}
+#define handle_to_gdb_pid handle_to_gdb_tid
+
 FORCEINLINE
 VOID
 InitManipulateFromStateChange(
@@ -51,8 +66,8 @@ typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
 );
 
 /* gdb_input.c */
-extern HANDLE gdb_dbg_thread;
-extern HANDLE gdb_dbg_process;
+extern UINT_PTR gdb_dbg_tid;
+extern UINT_PTR gdb_dbg_pid;
 extern KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
 extern KDSTATUS gdb_receive_and_interpret_packet(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
 
@@ -79,11 +94,18 @@ extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
 extern CONTEXT CurrentContext;
 extern DBGKD_GET_VERSION64 KdVersion;
 extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
+extern LIST_ENTRY* ProcessListHead;
 extern KDP_SEND_HANDLER KdpSendPacketHandler;
 extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler;
 /* Commone ManipulateState handlers */
 extern KDSTATUS ContinueManipulateStateHandler(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
 extern KDSTATUS SetContextManipulateHandler(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
+extern PEPROCESS TheIdleProcess;
+extern PETHREAD TheIdleThread;
+
+/* utils.c */
+extern PEPROCESS find_process( _In_ UINT_PTR Pid);
+extern PETHREAD find_thread(_In_ UINT_PTR Pid, _In_ UINT_PTR Tid);
 
 /* arch_sup.c */
 extern KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
index 238c4db..4376d4e 100644 (file)
@@ -14,18 +14,20 @@ FirstSendHandler(
     _In_ ULONG PacketType,
     _In_ PSTRING MessageHeader,
     _In_ PSTRING MessageData);
-static BOOLEAN CanSendData = FALSE;
+static BOOLEAN InException = FALSE;
 
 /* GLOBALS ********************************************************************/
 DBGKD_GET_VERSION64 KdVersion;
 KDDEBUGGER_DATA64* KdDebuggerDataBlock;
-BOOLEAN InException = FALSE;
+LIST_ENTRY* ProcessListHead;
 /* Callbacks used to communicate with KD aside from GDB */
 KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
 KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
 /* Data describing the current exception */
 DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
 CONTEXT CurrentContext;
+PEPROCESS TheIdleProcess;
+PETHREAD TheIdleThread;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
@@ -130,6 +132,8 @@ static
 void
 send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
 {
+    InException = TRUE;
+
     switch (StateChange->NewState)
     {
     case DbgKdLoadSymbolsStateChange:
@@ -139,17 +143,22 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
         break;
     }
     case DbgKdExceptionStateChange:
+    {
+        PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
         /* Save current state for later GDB queries */
         CurrentStateChange = *StateChange;
-        /* Unless GDB tells us otherwise, those are what we should have */
-        gdb_dbg_thread = PsGetThreadId((PETHREAD)(ULONG_PTR)StateChange->Thread);
-        gdb_dbg_process = PsGetThreadProcessId((PETHREAD)(ULONG_PTR)StateChange->Thread);
+        KDDBGPRINT("Exception 0x%08x in thread p%p.%p.\n",
+            StateChange->u.Exception.ExceptionRecord.ExceptionCode,
+            PsGetThreadProcessId(Thread),
+            PsGetThreadId(Thread));
+        /* Set the current debugged process/thread accordingly */
+        gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
+        gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
         gdb_send_exception();
         /* Next receive call will ask for the context */
         KdpManipulateStateHandler = GetContextManipulateHandler;
-        /* We can now send data, since after this we will be connected to GDB */
-        CanSendData = TRUE;
         break;
+    }
     default:
         /* FIXME */
         while (1);
@@ -162,7 +171,7 @@ send_kd_debug_io(
     _In_ DBGKD_DEBUG_IO* DebugIO,
     _In_ PSTRING String)
 {
-    if (!CanSendData)
+    if (InException)
         return;
 
     switch (DebugIO->ApiNumber)
@@ -217,6 +226,9 @@ ContinueManipulateStateHandler(
     /* We definitely are at the end of the send <-> receive loop, if any */
     KdpSendPacketHandler = NULL;
     KdpManipulateStateHandler = NULL;
+    /* We're not handling an exception anymore */
+    InException = FALSE;
+
     return KdPacketReceived;
 }
 
@@ -244,10 +256,11 @@ GetVersionSendHandler(
     RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
     DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
     KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
+    ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
 
-    /* We can tell KD to continue */
+    /* Now we can get the context for the current state */
     KdpSendPacketHandler = NULL;
-    KdpManipulateStateHandler = ContinueManipulateStateHandler;
+    KdpManipulateStateHandler = GetContextManipulateHandler;
 }
 
 static
@@ -267,9 +280,6 @@ GetVersionManipulateStateHandler(
     KdpSendPacketHandler = GetVersionSendHandler;
     KdpManipulateStateHandler = NULL;
 
-    /* This will make KD breakin and we will be able to properly attach to GDB */
-    KdContext->KdpControlCPending = TRUE;
-
     return KdPacketReceived;
 }
 
@@ -281,6 +291,7 @@ FirstSendHandler(
     _In_ PSTRING MessageData)
 {
     DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
+    PETHREAD Thread;
 
     if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
     {
@@ -296,7 +307,19 @@ FirstSendHandler(
         while(1);
     }
 
+    KDDBGPRINT("KDGDB: START!\n");
+
+    Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
+
+    /* Set up the current state */
     CurrentStateChange = *StateChange;
+    gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
+    gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
+    /* This is the idle process. Save it! */
+    TheIdleThread = Thread;
+    TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process;
+
+    KDDBGPRINT("Pid Tid of the first message: %" PRIxPTR", %" PRIxPTR ".\n", gdb_dbg_pid, gdb_dbg_tid);
 
     /* The next receive call will be asking for the version data */
     KdpSendPacketHandler = NULL;
diff --git a/reactos/drivers/base/kdgdb/utils.c b/reactos/drivers/base/kdgdb/utils.c
new file mode 100644 (file)
index 0000000..01dea3d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * COPYRIGHT:       GPL, see COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            drivers/base/kddll/utils.c
+ * PURPOSE:         Misc helper functions.
+ */
+
+#include "kdgdb.h"
+
+/*
+ * We cannot use PsLookupProcessThreadByCid or alike as we could be running at any IRQL.
+ * So we have to loop over the process list.
+ */
+
+PEPROCESS
+find_process(
+    _In_ UINT_PTR Pid)
+{
+    HANDLE ProcessId = gdb_pid_to_handle(Pid);
+    LIST_ENTRY* ProcessEntry;
+    PEPROCESS Process;
+
+    /* Special case for idle process */
+    if (Pid == 1)
+        return TheIdleProcess;
+
+    for (ProcessEntry = ProcessListHead->Flink;
+            ProcessEntry != ProcessListHead;
+            ProcessEntry = ProcessEntry->Flink)
+    {
+        Process = CONTAINING_RECORD(ProcessEntry, EPROCESS, ActiveProcessLinks);
+
+        if (Process->UniqueProcessId == ProcessId)
+            return Process;
+    }
+
+    return NULL;
+}
+
+PETHREAD
+find_thread(
+    _In_ UINT_PTR Pid,
+    _In_ UINT_PTR Tid)
+{
+    HANDLE ThreadId = gdb_tid_to_handle(Tid);
+    PETHREAD Thread;
+    PEPROCESS Process;
+    LIST_ENTRY* ThreadEntry;
+
+    /* Special case for the idle thread */
+    if ((Pid == 1) && (Tid == 1))
+        return TheIdleThread;
+
+    Process = find_process(Pid);
+    if (!Process)
+        return NULL;
+
+    for (ThreadEntry = Process->ThreadListHead.Flink;
+            ThreadEntry != &Process->ThreadListHead;
+            ThreadEntry = ThreadEntry->Flink)
+    {
+        Thread = CONTAINING_RECORD(ThreadEntry, ETHREAD, ThreadListEntry);
+        /* For GDB, Tid == 0 means any thread */
+        if ((Thread->Cid.UniqueThread == ThreadId) || (Tid == 0))
+        {
+            return Thread;
+        }
+    }
+
+    return NULL;
+}