#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 */
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 ***********************************************************/
/******************************************************************************
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)