[KDGDB]
[reactos.git] / reactos / drivers / base / kdgdb / kdpacket.c
index 9d29826..7f86b37 100644 (file)
 
 #include "kdgdb.h"
 
-/* GLOBALS ********************************************************************/
+/* LOCALS *********************************************************************/
+static
+VOID
+FirstSendHandler(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData);
 
-DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
+/* GLOBALS ********************************************************************/
 DBGKD_GET_VERSION64 KdVersion;
 KDDEBUGGER_DATA64* KdDebuggerDataBlock;
+BOOLEAN InException = FALSE;
 /* Callbacks used to communicate with KD aside from GDB */
-KDP_SEND_HANDLER KdpSendPacketHandler = NULL;
+KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
 KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
-
-/* LOCALS *********************************************************************/
-static BOOLEAN FakeNextManipulatePacket = FALSE;
-static DBGKD_MANIPULATE_STATE64 FakeManipulateState = {0};
+/* Data describing the current exception */
+DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
+CONTEXT CurrentContext;
 
 /* PRIVATE FUNCTIONS **********************************************************/
+
 static
-void
-send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
+VOID
+GetContextSendHandler(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData
+)
 {
-    static BOOLEAN first = TRUE;
+    DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
+    const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
 
-    /* Save current state for later GDB queries */
-    CurrentStateChange = *StateChange;
+    if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
+            || (State->ApiNumber != DbgKdGetContextApi)
+            || (MessageData->Length < sizeof(*Context)))
+    {
+        /* Should we bugcheck ? */
+        KDDBGPRINT("ERROR: Received wrong packet from KD.\n");
+        while (1);
+    }
+
+    /* Just copy it */
+    RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
+    KdpSendPacketHandler = NULL;
+}
+
+static
+KDSTATUS
+GetContextManipulateHandler(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext
+)
+{
+    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 = GetContextSendHandler;
+    KdpManipulateStateHandler = NULL;
 
-    if (first)
+    return KdPacketReceived;
+}
+
+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))
     {
-        /*
-         * This is the first packet we receive.
-         * We take this as an opportunity to connect with GDB and to
-         * get the KD version block
-         */
-        FakeNextManipulatePacket = TRUE;
-        FakeManipulateState.ApiNumber = DbgKdGetVersionApi;
-        FakeManipulateState.Processor = StateChange->Processor;
-        FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
-        FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
-
-        first = FALSE;
-        return;
+        /* Should we bugcheck ? */
+        while (1);
+    }
+
+    KdpSendPacketHandler = NULL;
+}
+
+KDSTATUS
+SetContextManipulateHandler(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext
+)
+{
+    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 = NULL;
+
+    return KdPacketReceived;
+}
+
+static
+void
+send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
+{
     switch (StateChange->NewState)
     {
     case DbgKdLoadSymbolsStateChange:
     {
         /* We don't care about symbols loading */
-        FakeNextManipulatePacket = TRUE;
-        FakeManipulateState.ApiNumber = DbgKdContinueApi;
-        FakeManipulateState.Processor = StateChange->Processor;
-        FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
-        FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
-        FakeManipulateState.u.Continue.ContinueStatus = STATUS_SUCCESS;
+        KdpManipulateStateHandler = ContinueManipulateStateHandler;
         break;
     }
     case DbgKdExceptionStateChange:
+        /* 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_send_exception();
+        /* Next receive call will ask for the context */
+        KdpManipulateStateHandler = GetContextManipulateHandler;
         break;
     default:
         /* FIXME */
@@ -100,21 +184,119 @@ send_kd_state_manipulate(
         gdb_send_registers((CONTEXT*)MessageData->Buffer);
         return;
 #endif
-    case DbgKdGetVersionApi:
-    {
-        LIST_ENTRY* DebuggerDataList;
-        /* Simply get a copy */
-        RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
-        DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
-        KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
-        return;
-    }
     default:
         /* FIXME */
         while (1);
     }
 }
 
+KDSTATUS
+ContinueManipulateStateHandler(
+    _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;
+    return KdPacketReceived;
+}
+
+static
+VOID
+GetVersionSendHandler(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData)
+{
+    DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
+    LIST_ENTRY* DebuggerDataList;
+
+    /* Confirm that all went well */
+    if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
+            || (State->ApiNumber != DbgKdGetVersionApi)
+            || !NT_SUCCESS(State->ReturnStatus))
+    {
+        /* FIXME: should detach from KD and go along without debugging */
+        KDDBGPRINT("Wrong packet received after asking for data.\n");
+        while(1);
+    }
+
+    /* Copy the relevant data */
+    RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
+    DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
+    KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
+
+    /* We can tell KD to continue */
+    KdpSendPacketHandler = NULL;
+    KdpManipulateStateHandler = ContinueManipulateStateHandler;
+}
+
+static
+KDSTATUS
+GetVersionManipulateStateHandler(
+    _Out_ DBGKD_MANIPULATE_STATE64* State,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG MessageLength,
+    _Inout_ PKD_CONTEXT KdContext)
+{
+    /* Ask for the version data */
+    State->ApiNumber = DbgKdGetVersionApi;
+    State->Processor = CurrentStateChange.Processor;
+    State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
+
+    /* The next send call will serve this query */
+    KdpSendPacketHandler = GetVersionSendHandler;
+    KdpManipulateStateHandler = NULL;
+
+    /* This will make KD breakin and we will be able to properly attach to GDB */
+    KdContext->KdpControlCPending = TRUE;
+
+    return KdPacketReceived;
+}
+
+static
+VOID
+FirstSendHandler(
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_ PSTRING MessageData)
+{
+    DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
+
+    if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
+    {
+        /* This is not the packet we are waiting for */
+        send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
+        return;
+    }
+
+    if (PacketType != PACKET_TYPE_KD_STATE_CHANGE64)
+    {
+        KDDBGPRINT("First KD packet is not a state change!\n");
+        /* FIXME: What should we send back to KD ? */
+        while(1);
+    }
+
+    CurrentStateChange = *StateChange;
+
+    /* The next receive call will be asking for the version data */
+    KdpSendPacketHandler = NULL;
+    KdpManipulateStateHandler = GetVersionManipulateStateHandler;
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 /******************************************************************************
@@ -162,13 +344,6 @@ KdReceivePacket(
     if (KdpManipulateStateHandler != NULL)
         return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
 
-    if (FakeNextManipulatePacket)
-    {
-        FakeNextManipulatePacket = FALSE;
-        *State = FakeManipulateState;
-        return KdPacketReceived;
-    }
-
     /* Receive data from GDB */
     Status = gdb_receive_packet(KdContext);
     if (Status != KdPacketReceived)