Author: jgardou Date: Sun Sep 14 20:45:30 2014 New Revision: 64154
URL: http://svn.reactos.org/svn/reactos?rev=64154&view=rev Log: [KDGDB] - Always pass down the result of gdb_receive_packet up to KD, so that it knows when a breakin packet was received. (CTRL-C) now works! - Generalize the use of the Send <-> ManipulateState callbacks for a better code reading. - Get the exception context as soon as it is thrown (instead of playing with the PRCB) - Improve the way we attach to GDB: on the first KD call, we set KdContext->ControlCPending so that KD throws an exception. That way we can first initialize our KD stuff, and then quietly attach to GDB - Implement the 'p' (get one register) GDB request. GDB is now much more reliable.
Modified: trunk/reactos/drivers/base/kdgdb/gdb_input.c trunk/reactos/drivers/base/kdgdb/gdb_send.c trunk/reactos/drivers/base/kdgdb/i386_sup.c trunk/reactos/drivers/base/kdgdb/kdgdb.h trunk/reactos/drivers/base/kdgdb/kdpacket.c
Modified: trunk/reactos/drivers/base/kdgdb/gdb_input.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/gdb_inpu... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/gdb_input.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/gdb_input.c [iso-8859-1] Sun Sep 14 20:45:30 2014 @@ -11,12 +11,13 @@
/* LOCALS *********************************************************************/ static HANDLE gdb_run_thread; -static HANDLE gdb_dbg_process; -HANDLE gdb_dbg_thread; -CONTEXT CurrentContext; /* 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;
/* PRIVATE FUNCTIONS **********************************************************/ static @@ -68,6 +69,7 @@ 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; @@ -90,6 +92,20 @@ } }
+KDSTATUS +gdb_receive_and_interpret_packet( + _Out_ DBGKD_MANIPULATE_STATE64* State, + _Out_ PSTRING MessageData, + _Out_ PULONG MessageLength, + _Inout_ PKD_CONTEXT KdContext) +{ + KDSTATUS Status = gdb_receive_packet(KdContext); + + if (Status != KdPacketReceived) + return Status; + return gdb_interpret_input(State, MessageData, MessageLength, KdContext); +} + static void handle_gdb_thread_alive(void) @@ -118,7 +134,7 @@
/* q* packets */ static -void +KDSTATUS handle_gdb_query( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, @@ -128,20 +144,20 @@ if (strncmp(gdb_input, "qSupported:", 11) == 0) { send_gdb_packet("PacketSize=4096;multiprocess+;"); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
if (strncmp(gdb_input, "qAttached", 9) == 0) { - /* Say yes: the remote server didn't create the process, ReactOS did! */ + /* Say no: We didn't attach, we create the process! */ send_gdb_packet("0"); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
if (strncmp(gdb_input, "qRcmd,", 6) == 0) { send_gdb_packet("OK"); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
if (strcmp(gdb_input, "qC") == 0) @@ -151,7 +167,7 @@ PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread), PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)); send_gdb_packet(gdb_out); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0) @@ -174,15 +190,13 @@ { /* there is only one thread to tell about */ send_gdb_packet("l"); - return; + 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 */ - gdb_receive_packet(KdContext); - gdb_interpret_input(State, MessageData, MessageLength, KdContext); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
if (Resuming) @@ -197,7 +211,7 @@ { /* We're done */ send_gdb_packet("l"); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks); @@ -234,9 +248,7 @@ /* send what we got */ send_gdb_packet(gdb_out); /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */ - gdb_receive_packet(KdContext); - gdb_interpret_input(State, MessageData, MessageLength, KdContext); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } }
@@ -244,13 +256,12 @@ send_gdb_packet(gdb_out); CurrentThreadEntry = NULL; /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */ - gdb_receive_packet(KdContext); - gdb_interpret_input(State, MessageData, MessageLength, KdContext); - return; + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input); send_gdb_packet(""); + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
#if 0 @@ -304,6 +315,7 @@ else send_gdb_memory(MessageData->Buffer, MessageData->Length); KdpSendPacketHandler = NULL; + KdpManipulateStateHandler = NULL; }
static @@ -331,150 +343,6 @@ }
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)); - KdpSendPacketHandler = NULL; -} - -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); - } - - KdpSendPacketHandler = NULL; -} - -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( _Out_ DBGKD_MANIPULATE_STATE64* State, @@ -499,6 +367,9 @@ { DBGKM_EXCEPTION64* Exception = NULL;
+ /* Tell GDB everything is fine, we will handle it */ + send_gdb_packet("OK"); + if (CurrentStateChange.NewState == DbgKdExceptionStateChange) Exception = &CurrentStateChange.u.Exception;
@@ -506,15 +377,22 @@ 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); + ULONG_PTR ProgramCounter; + + /* So we must get past the breakpoint instruction */ + ProgramCounter = KdpGetContextPc(&CurrentContext); + KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE); + + SetContextManipulateHandler(State, MessageData, MessageLength, KdContext); + KdpManipulateStateHandler = ContinueManipulateStateHandler; return KdPacketReceived; }
- return SendContinue(State, MessageData, MessageLength, KdContext); - } - } - + return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext); + } + } + + KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input); return KdPacketReceived; }
@@ -526,7 +404,6 @@ _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext) { - KDSTATUS Status; switch (gdb_input[0]) { case '?': @@ -534,16 +411,16 @@ gdb_send_exception(); break; case 'g': - gdb_send_registers(); - break; + return gdb_send_registers(State, MessageData, MessageLength, KdContext); case 'H': handle_gdb_set_thread(); break; case 'm': return handle_gdb_read_mem(State, MessageData, MessageLength); + case 'p': + return gdb_send_register(State, MessageData, MessageLength, KdContext); case 'q': - handle_gdb_query(State, MessageData, MessageLength, KdContext); - break; + return handle_gdb_query(State, MessageData, MessageLength, KdContext); case 'T': handle_gdb_thread_alive(); break; @@ -552,12 +429,8 @@ default: /* We don't know how to handle this request. Maybe this is something for KD */ State->ReturnStatus = STATUS_NOT_SUPPORTED; + KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input); return KdPacketReceived; } - /* Get the answer from GDB */ - Status = gdb_receive_packet(KdContext); - if (Status != KdPacketReceived) - return Status; - /* Try interpreting this new packet */ - return gdb_interpret_input(State, MessageData, MessageLength, KdContext); -} + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); +}
Modified: trunk/reactos/drivers/base/kdgdb/gdb_send.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/gdb_send... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/gdb_send.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/gdb_send.c [iso-8859-1] Sun Sep 14 20:45:30 2014 @@ -168,17 +168,12 @@ { char gdb_out[1024]; char* ptr = gdb_out; - DBGKM_EXCEPTION64* Exception = NULL; - - if (CurrentStateChange.NewState == DbgKdExceptionStateChange) - Exception = &CurrentStateChange.u.Exception; + DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception;
/* Report to GDB */ *ptr++ = 'T'; - if (Exception) - ptr = exception_code_to_gdb(Exception->ExceptionRecord.ExceptionCode, ptr); - else - ptr += sprintf(ptr, "05"); + + 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));
Modified: trunk/reactos/drivers/base/kdgdb/i386_sup.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/i386_sup... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/i386_sup.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/i386_sup.c [iso-8859-1] Sun Sep 14 20:45:30 2014 @@ -79,21 +79,48 @@ return 0; }
-void -gdb_send_registers(void) +KDSTATUS +gdb_send_registers( + _Out_ DBGKD_MANIPULATE_STATE64* State, + _Out_ PSTRING MessageData, + _Out_ PULONG MessageLength, + _Inout_ PKD_CONTEXT KdContext) { - CONTEXT* ctx; - PKPRCB* ProcessorBlockLists; ULONG32 Registers[16]; unsigned i; unsigned short size;
- ProcessorBlockLists = (PKPRCB*)KdDebuggerDataBlock->KiProcessorBlock.Pointer; - ctx = (CONTEXT*)((char*)ProcessorBlockLists[CurrentStateChange.Processor] + KdDebuggerDataBlock->OffsetPrcbProcStateContext); - for(i=0; i < 16; i++) { - Registers[i] = *(ULONG32*)ctx_to_reg(ctx, i, &size); + Registers[i] = *(ULONG32*)ctx_to_reg(&CurrentContext, i, &size); } send_gdb_memory(Registers, sizeof(Registers)); + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } + +KDSTATUS +gdb_send_register( + _Out_ DBGKD_MANIPULATE_STATE64* State, + _Out_ PSTRING MessageData, + _Out_ PULONG MessageLength, + _Inout_ PKD_CONTEXT KdContext) +{ + enum reg_name reg_name; + void *ptr; + unsigned short size; + + /* 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 (!ptr) + { + /* Undefined. Let's assume 32 bit register */ + send_gdb_packet("xxxxxxxx"); + } + else + { + send_gdb_memory(ptr, size); + } + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); +}
Modified: trunk/reactos/drivers/base/kdgdb/kdgdb.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/kdgdb.h?... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/kdgdb.h [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/kdgdb.h [iso-8859-1] Sun Sep 14 20:45:30 2014 @@ -25,6 +25,18 @@ #define KDDBGPRINT KdpDbgPrint #endif
+FORCEINLINE +VOID +InitManipulateFromStateChange( + _In_ ULONG ApiNumber, + _In_ const DBGKD_ANY_WAIT_STATE_CHANGE* StateChange, + _Out_ DBGKD_MANIPULATE_STATE64* Manipulate) +{ + Manipulate->ApiNumber = ApiNumber; + Manipulate->Processor = StateChange->Processor; + Manipulate->ProcessorLevel = StateChange->ProcessorLevel; +} + /* Callbacks to simulate a KdReceive <-> KdSend loop without GDB being aware of it */ typedef VOID (*KDP_SEND_HANDLER)( _In_ ULONG PacketType, @@ -40,7 +52,9 @@
/* 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); +extern HANDLE gdb_dbg_process; +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);
/* gdb_receive.c */ extern CHAR gdb_input[]; @@ -61,14 +75,18 @@
/* kdpacket.c */ extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange; +extern CONTEXT CurrentContext; extern DBGKD_GET_VERSION64 KdVersion; extern KDDEBUGGER_DATA64* KdDebuggerDataBlock; 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);
/* arch_sup.c */ -void gdb_send_registers(void); +extern KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); +extern KDSTATUS gdb_send_registers(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */ #ifdef _M_IX86
Modified: trunk/reactos/drivers/base/kdgdb/kdpacket.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/kdpacket... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/kdpacket.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/kdpacket.c [iso-8859-1] Sun Sep 14 20:45:30 2014 @@ -7,61 +7,145 @@
#include "kdgdb.h"
+/* LOCALS *********************************************************************/ +static +VOID +FirstSendHandler( + _In_ ULONG PacketType, + _In_ PSTRING MessageHeader, + _In_ PSTRING MessageData); + /* GLOBALS ********************************************************************/ - -DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange; 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 +GetContextSendHandler( + _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 ? */ + 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; + + 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)) + { + /* 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) { - static BOOLEAN first = TRUE; - - /* Save current state for later GDB queries */ - CurrentStateChange = *StateChange; - - if (first) - { - /* - * 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; - } - 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,19 +184,117 @@ 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 @@ 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)