- 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.

svn path=/trunk/; revision=64154
This commit is contained in:
Jérôme Gardou
2014-09-14 20:45:30 +00:00
parent fe8e1d19fb
commit 31965e9804
5 changed files with 336 additions and 248 deletions
+51 -178
View File
@@ -11,13 +11,14 @@
/* 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
HANDLE
@@ -68,6 +69,7 @@ handle_gdb_set_thread(void)
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 @@ handle_gdb_set_thread(void)
}
}
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 @@ handle_gdb_thread_alive(void)
/* q* packets */
static
void
KDSTATUS
handle_gdb_query(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
@@ -128,20 +144,20 @@ handle_gdb_query(
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 @@ handle_gdb_query(
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 @@ handle_gdb_query(
{
/* 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 @@ handle_gdb_query(
{
/* 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 @@ handle_gdb_query(
/* 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 @@ handle_gdb_query(
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 @@ ReadMemorySendHandler(
else
send_gdb_memory(MessageData->Buffer, MessageData->Length);
KdpSendPacketHandler = NULL;
KdpManipulateStateHandler = NULL;
}
static
@@ -330,150 +342,6 @@ 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));
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(
@@ -499,6 +367,9 @@ handle_gdb_v(
{
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 @@ handle_gdb_v(
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 @@ gdb_interpret_input(
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
KDSTATUS Status;
switch (gdb_input[0])
{
case '?':
@@ -534,16 +411,16 @@ gdb_interpret_input(
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 @@ gdb_interpret_input(
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);
}
+3 -8
View File
@@ -168,17 +168,12 @@ gdb_send_exception(void)
{
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));
+35 -8
View File
@@ -79,21 +79,48 @@ ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size)
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);
}
+21 -3
View File
@@ -25,6 +25,18 @@ extern ULONG KdpDbgPrint(const char* Format, ...);
#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 @@ typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
/* 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 @@ KDSTATUS NTAPI KdpReceiveByte(_Out_ PUCHAR OutByte);
/* 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
+226 -51
View File
@@ -7,61 +7,145 @@
#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
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,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)