[KDGDB]
authorJérôme Gardou <jerome.gardou@reactos.org>
Fri, 12 Sep 2014 20:23:08 +0000 (20:23 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Fri, 12 Sep 2014 20:23:08 +0000 (20:23 +0000)
 - Add a callback mechanism permitting to "simulate" KD send <-> receive loop without having to actually communicate to GDB
 - Use that to update the program counter when cont'ing a breakpoint
Now cont'ing an assertion failure is possible, since we actually get beyond the int 3 instruction

svn path=/trunk/; revision=64127

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

index 2305055..4e85422 100644 (file)
@@ -11,6 +11,7 @@
 static HANDLE gdb_run_thread;
 static HANDLE gdb_dbg_process;
 HANDLE gdb_dbg_thread;
+CONTEXT CurrentContext;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 static
@@ -199,6 +200,147 @@ handle_gdb_read_mem(
     return KdPacketReceived;
 }
 
+static
+VOID
+GetCurrentContextSendHandler(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData
+)
+{
+    DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
+    const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
+
+    if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
+            || (State->ApiNumber != DbgKdGetContextApi)
+            || (MessageData->Length < sizeof(*Context)))
+    {
+        /* Should we bugcheck ? */
+        while (1);
+    }
+
+    /* Just copy it */
+    RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
+}
+
+static
+VOID
+GetCurrentContext(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext,
+    _In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
+)
+{
+    State->ApiNumber = DbgKdGetContextApi;
+    State->Processor = CurrentStateChange.Processor;
+    State->ReturnStatus = STATUS_SUCCESS;
+    State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
+    MessageData->Length = 0;
+
+    /* Update the send <-> receive loop handler */
+    KdpSendPacketHandler = GetCurrentContextSendHandler;
+    KdpManipulateStateHandler = ManipulateStateHandler;
+}
+
+static
+VOID
+SetContextSendHandler(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData
+)
+{
+    DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
+
+    /* We just confirm that all went well */
+    if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
+            || (State->ApiNumber != DbgKdSetContextApi)
+            || (State->ReturnStatus != STATUS_SUCCESS))
+    {
+        /* Should we bugcheck ? */
+        while (1);
+    }
+}
+
+static
+KDSTATUS
+SetContext(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext,
+    _In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
+)
+{
+    State->ApiNumber = DbgKdSetContextApi;
+    State->Processor = CurrentStateChange.Processor;
+    State->ReturnStatus = STATUS_SUCCESS;
+    State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
+    MessageData->Length = sizeof(CurrentContext);
+
+    if (MessageData->MaximumLength < sizeof(CurrentContext))
+    {
+        while (1);
+    }
+
+    RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
+
+    /* Update the send <-> receive loop handlers */
+    KdpSendPacketHandler = SetContextSendHandler;
+    KdpManipulateStateHandler = ManipulateStateHandler;
+
+    return KdPacketReceived;
+}
+
+static
+KDSTATUS
+SendContinue(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext
+)
+{
+    /* Let's go on */
+    State->ApiNumber = DbgKdContinueApi;
+    State->ReturnStatus = STATUS_SUCCESS; /* ? */
+    State->Processor = CurrentStateChange.Processor;
+    State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
+    if (MessageData)
+        MessageData->Length = 0;
+    *MessageLength = 0;
+    State->u.Continue.ContinueStatus = STATUS_SUCCESS;
+
+    /* We definitely are at the end of the send <-> receive loop, if any */
+    KdpSendPacketHandler = NULL;
+    KdpManipulateStateHandler = NULL;
+
+    /* Tell GDB we are fine */
+    send_gdb_packet("OK");
+    return KdPacketReceived;
+}
+
+static
+KDSTATUS
+UpdateProgramCounterSendContinue(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext)
+{
+    ULONG_PTR ProgramCounter;
+
+    /* So we must get past the breakpoint instruction */
+    ProgramCounter = KdpGetContextPc(&CurrentContext);
+    KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
+
+    /* Set the context and continue */
+    SetContext(State, MessageData, MessageLength, KdContext, SendContinue);
+    return KdPacketReceived;
+}
+
 static
 KDSTATUS
 handle_gdb_v(
@@ -222,18 +364,21 @@ handle_gdb_v(
 
         if (strcmp(gdb_input, "vCont;c") == 0)
         {
-            /* Let's go on */
-            State->ApiNumber = DbgKdContinueApi;
-            State->ReturnStatus = STATUS_SUCCESS; /* ? */
-            State->Processor = CurrentStateChange.Processor;
-            State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
-            if (MessageData)
-                MessageData->Length = 0;
-            *MessageLength = 0;
-            State->u.Continue.ContinueStatus = STATUS_SUCCESS;
-            /* Tell GDB we are fine */
-            send_gdb_packet("OK");
-            return KdPacketReceived;
+            DBGKM_EXCEPTION64* Exception = NULL;
+
+            if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
+                Exception = &CurrentStateChange.u.Exception;
+
+            /* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
+            if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
+                    && (Exception->ExceptionRecord.ExceptionInformation[0] == 0))
+            {
+                /* So we get the context, update it and send it back */
+                GetCurrentContext(State, MessageData, MessageLength, KdContext, UpdateProgramCounterSendContinue);
+                return KdPacketReceived;
+            }
+
+            return SendContinue(State, MessageData, MessageLength, KdContext);
         }
     }
 
index 37b5510..e330f3e 100644 (file)
@@ -25,6 +25,19 @@ extern ULONG KdpDbgPrint(const char* Format, ...);
 #define KDDBGPRINT KdpDbgPrint
 #endif
 
+/* Callbacks to simulate a KdReceive <-> KdSend loop without GDB being aware of it */
+typedef VOID (*KDP_SEND_HANDLER)(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData
+);
+typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext
+);
+
 /* gdb_input.c */
 extern HANDLE gdb_dbg_thread;
 KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
@@ -49,8 +62,22 @@ KDSTATUS NTAPI KdpReceiveByte(_Out_ PUCHAR OutByte);
 extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
 extern DBGKD_GET_VERSION64 KdVersion;
 extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
+extern KDP_SEND_HANDLER KdpSendPacketHandler;
+extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler;
+
 
 /* arch_sup.c */
 void gdb_send_registers(void);
 
+/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
+#ifdef _M_IX86
+#  define KdpGetContextPc(Context) \
+    ((Context)->Eip)
+#  define KdpSetContextPc(Context, ProgramCounter) \
+    ((Context)->Eip = (ProgramCounter))
+#  define KD_BREAKPOINT_SIZE        sizeof(UCHAR)
+#else
+#  error "Please define relevant macros for your architecture"
+#endif
+
 #endif /* _KDGDB_H_ */
index adcf15b..dee08a8 100644 (file)
@@ -12,6 +12,9 @@
 DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
 DBGKD_GET_VERSION64 KdVersion;
 KDDEBUGGER_DATA64* KdDebuggerDataBlock;
+/* Callbacks used to communicate with KD aside from GDB */
+KDP_SEND_HANDLER KdpSendPacketHandler = NULL;
+KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
 
 /* LOCALS *********************************************************************/
 static BOOLEAN FakeNextManipulatePacket = FALSE;
@@ -159,6 +162,10 @@ KdReceivePacket(
 
     State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
 
+    /* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
+    if (KdpManipulateStateHandler != NULL)
+        return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
+
     if (FakeNextManipulatePacket)
     {
         FakeNextManipulatePacket = FALSE;
@@ -183,6 +190,13 @@ KdSendPacket(
     IN PSTRING MessageData,
     IN OUT PKD_CONTEXT KdContext)
 {
+    /* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
+    if (KdpSendPacketHandler)
+    {
+        KdpSendPacketHandler(PacketType, MessageHeader, MessageData);
+        return;
+    }
+
     switch (PacketType)
     {
     case PACKET_TYPE_KD_STATE_CHANGE64: