[KDGDB]
authorJérôme Gardou <jerome.gardou@reactos.org>
Sun, 14 Sep 2014 22:50:10 +0000 (22:50 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Sun, 14 Sep 2014 22:50:10 +0000 (22:50 +0000)
 - Fix an embarassing works-for-me but uncommited cast.
 - Add support for reading registers and memory from foreign threads. Highly experimental and nearly untested, use at your own risk.

svn path=/trunk/; revision=64156

reactos/drivers/base/kdgdb/gdb_input.c
reactos/drivers/base/kdgdb/i386_sup.c
reactos/drivers/base/kdgdb/kdgdb.h
reactos/drivers/base/kdgdb/kdpacket.c

index f58e66b..b858a38 100644 (file)
@@ -11,6 +11,8 @@
 
 /* LOCALS *********************************************************************/
 static HANDLE gdb_run_thread;
+/* We might have to attach to a process to read its memory */
+static PEPROCESS AttachedProcess = NULL;
 /* Keep track of where we are for qfThreadInfo/qsThreadInfo */
 static LIST_ENTRY* CurrentProcessEntry;
 static LIST_ENTRY* CurrentThreadEntry;
@@ -316,6 +318,13 @@ ReadMemorySendHandler(
         send_gdb_memory(MessageData->Buffer, MessageData->Length);
     KdpSendPacketHandler = NULL;
     KdpManipulateStateHandler = NULL;
+
+    /* Detach if we have to */
+    if (AttachedProcess != NULL)
+    {
+        KeDetachProcess();
+        AttachedProcess = NULL;
+    }
 }
 
 static
@@ -323,7 +332,8 @@ KDSTATUS
 handle_gdb_read_mem(
     _Out_ DBGKD_MANIPULATE_STATE64* State,
     _Out_ PSTRING MessageData,
-    _Out_ PULONG MessageLength)
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext)
 {
     State->ApiNumber = DbgKdReadVirtualMemoryApi;
     State->ReturnStatus = STATUS_SUCCESS; /* ? */
@@ -333,6 +343,19 @@ handle_gdb_read_mem(
         MessageData->Length = 0;
     *MessageLength = 0;
 
+    /* Attach to the debug process to read its memory */
+    if (gdb_dbg_process != PsGetCurrentProcessId())
+    {
+        NTSTATUS Status = PsLookupProcessByProcessId(gdb_dbg_process, &AttachedProcess);
+        if (!NT_SUCCESS(Status))
+        {
+            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);
+    }
+
     State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
     State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
 
@@ -416,7 +439,7 @@ gdb_interpret_input(
         handle_gdb_set_thread();
         break;
     case 'm':
-        return handle_gdb_read_mem(State, MessageData, MessageLength);
+        return handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
     case 'p':
         return gdb_send_register(State, MessageData, MessageLength, KdContext);
     case 'q':
index 16cceb1..dc752b5 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "kdgdb.h"
 
+#include <pstypes.h>
+
 enum reg_name
 {
     EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
@@ -79,6 +81,44 @@ ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size)
     return 0;
 }
 
+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)
+    {
+        return NULL;
+    }
+
+    *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);
+    }
+    return NULL;
+}
+
 KDSTATUS
 gdb_send_registers(
     _Out_ DBGKD_MANIPULATE_STATE64* State,
@@ -86,15 +126,62 @@ gdb_send_registers(
     _Out_ PULONG MessageLength,
     _Inout_ PKD_CONTEXT KdContext)
 {
-    ULONG32 Registers[16];
+    CHAR Registers[16*8 + 1];
+    UCHAR* RegisterPtr;
     unsigned i;
     unsigned short size;
+    CHAR* ptr = Registers;
 
-    for(i=0; i < 16; i++)
+    if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
     {
-        Registers[i] = *(ULONG32*)ctx_to_reg(&CurrentContext, i, &size);
+        for(i=0; i < 16; i++)
+        {
+            RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
+            *ptr++ = hex_chars[RegisterPtr[0] >> 4];
+            *ptr++ = hex_chars[RegisterPtr[0] & 0xF];
+            *ptr++ = hex_chars[RegisterPtr[1] >> 4];
+            *ptr++ = hex_chars[RegisterPtr[1] & 0xF];
+            *ptr++ = hex_chars[RegisterPtr[2] >> 4];
+            *ptr++ = hex_chars[RegisterPtr[2] & 0xF];
+            *ptr++ = hex_chars[RegisterPtr[3] >> 4];
+            *ptr++ = hex_chars[RegisterPtr[3] & 0xF];
+        }
     }
-    send_gdb_memory(Registers, sizeof(Registers));
+    else
+    {
+        PETHREAD DbgThread;
+        NTSTATUS Status;
+
+        Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Thread is dead */
+            send_gdb_packet("E03");
+            return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
+        }
+
+        for(i=0; i < 16; i++)
+        {
+            RegisterPtr = thread_to_reg(DbgThread, i, &size);
+            if (RegisterPtr)
+            {
+                *ptr++ = hex_chars[RegisterPtr[0] >> 4];
+                *ptr++ = hex_chars[RegisterPtr[0] & 0xF];
+                *ptr++ = hex_chars[RegisterPtr[1] >> 4];
+                *ptr++ = hex_chars[RegisterPtr[1] & 0xF];
+                *ptr++ = hex_chars[RegisterPtr[2] >> 4];
+                *ptr++ = hex_chars[RegisterPtr[2] & 0xF];
+                *ptr++ = hex_chars[RegisterPtr[3] >> 4];
+                *ptr++ = hex_chars[RegisterPtr[3] & 0xF];
+            }
+            else
+            {
+                ptr += sprintf(ptr, "xxxxxxxx");
+            }
+        }
+    }
+    *ptr = '\0';
+    send_gdb_packet(Registers);
     return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
 }
 
@@ -112,7 +199,27 @@ gdb_send_register(
     /* Get the GDB register name (gdb_input = "pXX") */
     reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
 
-    ptr = ctx_to_reg(&CurrentContext, reg_name, &size);
+    if (gdb_dbg_thread == 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);
+    }
+    else
+    {
+        PETHREAD DbgThread;
+        NTSTATUS Status;
+
+        Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Thread is dead */
+            send_gdb_packet("E03");
+            return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
+        }
+
+        ptr = thread_to_reg(DbgThread, reg_name, &size);
+    }
+
     if (!ptr)
     {
         /* Undefined. Let's assume 32 bit register */
@@ -122,5 +229,6 @@ gdb_send_register(
     {
         send_gdb_memory(ptr, size);
     }
+
     return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
 }
index bc18e5b..71f788d 100644 (file)
@@ -67,6 +67,7 @@ void send_gdb_memory(_In_ VOID* Buffer, size_t Length);
 void gdb_send_debug_io(_In_ PSTRING String);
 void gdb_send_exception(void);
 void send_gdb_ntstatus(_In_ NTSTATUS Status);
+extern const char hex_chars[];
 
 /* kdcom.c */
 KDSTATUS NTAPI KdpPollBreakIn(VOID);
index 7f86b37..238c4db 100644 (file)
@@ -14,6 +14,7 @@ FirstSendHandler(
     _In_ ULONG PacketType,
     _In_ PSTRING MessageHeader,
     _In_ PSTRING MessageData);
+static BOOLEAN CanSendData = FALSE;
 
 /* GLOBALS ********************************************************************/
 DBGKD_GET_VERSION64 KdVersion;
@@ -141,11 +142,13 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
         /* 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)StateChange->Thread);
-        gdb_dbg_process = PsGetThreadProcessId((PETHREAD)StateChange->Thread);
+        gdb_dbg_thread = PsGetThreadId((PETHREAD)(ULONG_PTR)StateChange->Thread);
+        gdb_dbg_process = PsGetThreadProcessId((PETHREAD)(ULONG_PTR)StateChange->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 */
@@ -159,6 +162,9 @@ send_kd_debug_io(
     _In_ DBGKD_DEBUG_IO* DebugIO,
     _In_ PSTRING String)
 {
+    if (!CanSendData)
+        return;
+
     switch (DebugIO->ApiNumber)
     {
     case DbgKdPrintStringApi: